From b71920f68ee7240536fe0349a3576060a9314137 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 14 May 2025 14:17:29 +0000 Subject: [PATCH] fixed career_list save --- backend/server.js | 81 ++++++++---------- src/components/CareerExplorer.js | 138 +++++++++++++++++++++---------- user_profile.db | Bin 110592 -> 110592 bytes 3 files changed, 131 insertions(+), 88 deletions(-) diff --git a/backend/server.js b/backend/server.js index 8e0ef4f..bd80a8c 100755 --- a/backend/server.js +++ b/backend/server.js @@ -233,7 +233,7 @@ app.get('/api/check-username/:username', (req, res) => { }); }); -// Upsert user profile with career_priorities and career_list +// Upsert user profile (corrected and robust) app.post('/api/user-profile', (req, res) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) { @@ -262,75 +262,69 @@ app.post('/api/user-profile', (req, res) => { career_list, } = req.body; - if (!firstName || !lastName || !email || !zipCode || !state || !area) { - return res.status(400).json({ error: 'All fields are required (except interest_inventory_answers, career_priorities, career_list)' }); - } - - // Check for existing user profile - const checkQuery = `SELECT * FROM user_profile WHERE user_id = ?;`; - db.get(checkQuery, [userId], (err, existingRow) => { + // Check existing profile explicitly first + db.get(`SELECT * FROM user_profile WHERE user_id = ?;`, [userId], (err, existingRow) => { if (err) { console.error('Error checking profile:', err.message); return res.status(500).json({ error: 'Database error' }); } - // Preserve existing data if not provided - const finalAnswers = interest_inventory_answers === undefined - ? existingRow?.interest_inventory_answers || null - : interest_inventory_answers; + // Require fields ONLY if no existing profile found + if (!existingRow && (!firstName || !lastName || !email || !zipCode || !state || !area)) { + return res.status(400).json({ error: 'All fields are required for initial profile creation.' }); + } - const finalCareerPriorities = career_priorities === undefined - ? existingRow?.career_priorities || null - : career_priorities; + const finalAnswers = interest_inventory_answers !== undefined + ? interest_inventory_answers + : existingRow?.interest_inventory_answers || null; - const finalCareerList = career_list === undefined - ? existingRow?.career_list || null - : career_list; + const finalCareerPriorities = career_priorities !== undefined + ? career_priorities + : existingRow?.career_priorities || null; + + const finalCareerList = career_list !== undefined + ? career_list + : existingRow?.career_list || null; if (existingRow) { - // Update existing profile + // Update existing profile clearly const updateQuery = ` UPDATE user_profile - SET firstname = ?, - lastname = ?, - email = ?, - zipcode = ?, - state = ?, - area = ?, - career_situation = ?, - interest_inventory_answers = ?, - career_priorities = ?, - career_list = ? + SET firstname = ?, lastname = ?, email = ?, zipcode = ?, state = ?, area = ?, career_situation = ?, + interest_inventory_answers = ?, career_priorities = ?, career_list = ? WHERE user_id = ? `; const params = [ - firstName, - lastName, - email, - zipCode, - state, - area, + firstName || existingRow.firstname, + lastName || existingRow.lastname, + email || existingRow.email, + zipCode || existingRow.zipcode, + state || existingRow.state, + area || existingRow.area, careerSituation || existingRow.career_situation, finalAnswers, finalCareerPriorities, finalCareerList, userId, ]; + db.run(updateQuery, params, function (err) { if (err) { - console.error('Error updating profile:', err.message); + console.error('Update error:', err.message); return res.status(500).json({ error: 'Failed to update user profile' }); } - return res.status(200).json({ message: 'User profile updated successfully' }); + res.status(200).json({ message: 'User profile updated successfully' }); }); + } else { - // Insert new profile + // Insert new profile clearly const insertQuery = ` INSERT INTO user_profile - (firstname, lastname, email, zipcode, state, area, career_situation, interest_inventory_answers, career_priorities, career_list, user_id) + (user_id, firstname, lastname, email, zipcode, state, area, career_situation, interest_inventory_answers, career_priorities, career_list) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `; const params = [ + userId, firstName, lastName, email, @@ -341,23 +335,20 @@ app.post('/api/user-profile', (req, res) => { finalAnswers, finalCareerPriorities, finalCareerList, - userId, ]; + db.run(insertQuery, params, function (err) { if (err) { - console.error('Error inserting profile:', err.message); + console.error('Insert error:', err.message); return res.status(500).json({ error: 'Failed to create user profile' }); } - return res - .status(201) - .json({ message: 'User profile created successfully', id: this.lastID }); + res.status(201).json({ message: 'User profile created successfully', id: this.lastID }); }); } }); }); - // Route to fetch user profile app.get('/api/user-profile', (req, res) => { const token = req.headers.authorization?.split(' ')[1]; diff --git a/src/components/CareerExplorer.js b/src/components/CareerExplorer.js index ee88606..50b2485 100644 --- a/src/components/CareerExplorer.js +++ b/src/components/CareerExplorer.js @@ -57,54 +57,98 @@ function CareerExplorer({ handleCareerClick, userState, areaTitle }) { return masterCareerRatings.find(c => c.soc_code === socCode)?.ratings || {}; }; + const saveCareerListToBackend = async (newCareerList) => { + try { + const token = localStorage.getItem('token'); + await axios.post(`${apiUrl}/user-profile`, { + // Provide all required fields from userProfile + // If your DB requires them, fill them in here: + firstName: userProfile?.firstname, + lastName: userProfile?.lastname, + email: userProfile?.email, + zipCode: userProfile?.zipcode, + state: userProfile?.state, + area: userProfile?.area, + careerSituation: userProfile?.career_situation, + + // For the rest, ensure we're not overwriting if not needed + interest_inventory_answers: userProfile?.interest_inventory_answers, + career_priorities: userProfile?.career_priorities, + + // IMPORTANT: We convert the newCareerList to JSON if your DB expects text + career_list: JSON.stringify(newCareerList), + }, { + headers: { Authorization: `Bearer ${token}` }, + }); + } catch (err) { + console.error('Error saving career_list:', err); + // optional: show a user-friendly error + } +}; + const addCareerToList = (career) => { - const masterRatings = getCareerRatingsBySocCode(career.code); - - const fitRatingMap = { - Best: 5, - Great: 4, - Good: 3, - }; - - const interestsRating = priorities.interests === 'I’m not sure yet' - ? parseInt(prompt('Rate your interest in this career (1-5):', '3'), 10) - : fitRatingMap[career.fit] || masterRatings.interests || 3; - - const meaningRating = parseInt(prompt('How meaningful is this career to you? (1-5):', '3'), 10); - - const stabilityRating = career.ratings && career.ratings.stability !== undefined - ? career.ratings.stability - : masterRatings.stability || 3; + const masterRatings = getCareerRatingsBySocCode(career.code); + + const fitRatingMap = { + Best: 5, + Great: 4, + Good: 3, + }; + + const interestsRating = + priorities.interests === "I’m not sure yet" + ? parseInt(prompt("Rate your interest in this career (1-5):", "3"), 10) + : fitRatingMap[career.fit] || masterRatings.interests || 3; + + const meaningRating = parseInt( + prompt("How meaningful is this career to you? (1-5):", "3"), + 10 + ); + + const stabilityRating = + career.ratings && career.ratings.stability !== undefined + ? career.ratings.stability + : masterRatings.stability || 3; + + const growthRating = masterRatings.growth || 3; + const balanceRating = masterRatings.balance || 3; + const recognitionRating = masterRatings.recognition || 3; + + const careerWithUserRatings = { + ...career, + ratings: { + interests: interestsRating, + meaning: meaningRating, + stability: stabilityRating, + growth: growthRating, + balance: balanceRating, + recognition: recognitionRating, + }, + }; + + setCareerList((prevList) => { + if (prevList.some((c) => c.code === career.code)) { + alert("Career already in comparison list."); + return prevList; + } + + const newList = [...prevList, careerWithUserRatings]; + // Call the API to save + saveCareerListToBackend(newList); + return newList; + }); +}; - const growthRating = masterRatings.growth || 3; - const balanceRating = masterRatings.balance || 3; - const recognitionRating = masterRatings.recognition || 3; - - const careerWithUserRatings = { - ...career, - ratings: { - interests: interestsRating, - meaning: meaningRating, - stability: stabilityRating, - growth: growthRating, - balance: balanceRating, - recognition: recognitionRating, - }, - }; - - setCareerList((prevList) => { - if (prevList.some((c) => c.code === career.code)) { - alert('Career already in comparison list.'); - return prevList; - } - return [...prevList, careerWithUserRatings]; - }); - }; const removeCareerFromList = (careerCode) => { - setCareerList((prevList) => prevList.filter((c) => c.code !== careerCode)); - }; + setCareerList((prevList) => { + const newList = prevList.filter((c) => c.code !== careerCode); + // Call the API to save + saveCareerListToBackend(newList); + return newList; + }); +}; useEffect(() => { const fetchUserProfile = async () => { @@ -118,6 +162,14 @@ function CareerExplorer({ handleCareerClick, userState, areaTitle }) { const profileData = res.data; setUserProfile(profileData); + if (profileData.career_list) { + try { + setCareerList(JSON.parse(profileData.career_list)); + } catch (err) { + console.error('Error parsing career_list:', err); + } + } + const priorities = profileData.career_priorities ? JSON.parse(profileData.career_priorities) : {}; diff --git a/user_profile.db b/user_profile.db index 3186c5e2e82d1e022c552f2b371c5cc84234db2d..7271ab09a48efd477e8be2603c120cbb2ae66d23 100644 GIT binary patch delta 3557 zcmcJRO^@3|7{^l;s^tI`2UH{|9p>y!Vkh3bhzsnZ3JKbks)A5em5DuZrgc1KX1v>N zwQ@_pK&u{l;=r8?2gHf5!MO)M2>)lCYYW@WT67-`cqN@a>I_*2bgJ z?`NN~i@Troqd1Q7i27l#ANIp2iu(A)y%>)e-@TAF!d}#i;(ni&@q{F{pZsIM@ukVc70=J3Qc1 z<)GrS)+s&`ol1PYkieQ#E~mxMO)^tXCeG5Ls58sQ_xZ%AZ02t1%H>+$;bUhi8So4@ z6?{Auxy6?#O9N}jw3#Xw%ZCBKttYqc!B#$w1D>lnw5L15iKBxM*pW6ds&q<2AK%SI z!9ag~uaV75wTOjuSLwI`fpSX8MjaBINybc*ZQq*8gRiVQ1mCLv_- zHWi7}Mv)k)*4QyeibW26x|GHpw7uW<4*b5scWSvOb6v8jDj<{SqA>+_vJzHWTp%1% zMUq#kWI|e~MF?OOf?*L3K|WbnMy4FyCz&?z&Iy%UHpRPg_Jnq_Vi!tkWRuxM3Gi%$71yh;ZXmz;H$yh3p5oGuI|y^2bV*bGVIH>l6v3*s~5IFyKV|ur1sC zX22zu^;{*pM&Cx^QM{<;EMg~XdV`Uu7Jj{;(qY$VovL#pto&XI!^crKikfdeMoSI4 z-GC#Xq)nzvksd@Ai@walXygTxnJ6+;=T_GrlZJX~d$Cye+ar{AQB)$oTFQbFz{kUg zM0Ju>rH{oGF+bTm0sHc9B1^}k3rpqzG&{z~yK6gxVI20l(1Dh*$&9)f zBMKh|#pKKKK37BobRKqk0iR1j1?%6@O%s(X2X`=rGo$wrLVBGb{+OP8+^3u*IzyNF z{^%bf?)B@^C*BMJxOO*uC4G)0kcB0EzQx4S>@wPk0SOptHD)*Mi`VB6u?i*m0z+{0 zR2U))YS1Uq7?M+PgaAa7e9v2%!Ajd^*ZfdCz!WVsfTZ>$qaEMxM(1)9oH$@}Nn=JO zn1dD=I$*gfmMFrG0i1xNiPD)79E#|ha^b#Mp#>(JIS>$ zZUcueb1m$8A|3-<-H`1&Iq~`2QJHc`=2sMd{G(d7DRn7&Y&pPB?cQ4N>VHxDjk>qi zyV_47?;iYnLs;t%qg6OrMYS69dKDSBwz|;@oSYVG4b_J6Dm0#;+A;pDG9&DbVnWi( rfL@2S<5U}L^+&Iy+I9a|@J(W^cX)X7=}({BdbEA%kL^om{(SroTn4gn delta 166 zcmZp8z}E19ZGtr8w23m#jMFwIEad0qd&t1d%gMm+%*)Bww6XCwk9boVrwD_%xS_b9 zKMRL!BP$0714pwZ!(?}X02@PNBNHQIV^b3oLlaX&6GLMYBcOnhDG-?$0R@aqjSY=} x;t)wAQ&VG8QzH`~2~;`xvcR>;Pvqi-7#J9m;N~-cj0c(B>@2_CS)Ot41OP5>CgK19