fixed career profile delete, simulator 50/50 defaults for pcts
Some checks failed
ci/woodpecker/manual/woodpecker Pipeline failed

This commit is contained in:
Josh 2025-09-18 15:27:06 +00:00
parent 20a1f796b5
commit 46b66df823
6 changed files with 62 additions and 30 deletions

View File

@ -1 +1 @@
408b293acaaa053b934050f88b9c93db41ecb097-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b
7c4503634c1566a112e17705d07e15f792647175-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b

View File

@ -27,7 +27,7 @@ const CANARY_SQL = `
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootPath = path.resolve(__dirname, '..');
const isProd = (process.env.ENV_NAME === 'prod');
const env = (process.env.ENV_NAME === 'prod');
const envPath = path.resolve(rootPath, `.env.${env}`);
dotenv.config({ path: envPath, override: false });

View File

@ -32,7 +32,7 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootPath = path.resolve(__dirname, '..');
const isProd = (process.env.ENV_NAME === 'prod');
const env = (process.env.ENV_NAME === 'prod');
const envPath = path.resolve(rootPath, `.env.${env}`);
dotenv.config({ path: envPath, override: false }); // don't clobber compose-injected env

View File

@ -3435,6 +3435,30 @@ app.post('/api/premium/financial-profile', authenticatePremiumUser, async (req,
extra_cash_retirement_pct
} = req.body;
// If the payload is empty, do not clobber existing values
if (!req.body || Object.keys(req.body).length === 0) {
return res.json({ message: 'No changes' });
}
// ---- Normalize split: numbers, clamp, complement, 50/50 fallback ----
function normalizeSplit(eIn, rIn) {
let e = Number(eIn), r = Number(rIn);
const finiteE = Number.isFinite(e), finiteR = Number.isFinite(r);
if (!finiteE && !finiteR) return { e: 50, r: 50 };
if (finiteE && !finiteR) { e = Math.min(Math.max(e, 0), 100); return { e, r: 100 - e }; }
if (!finiteE && finiteR) { r = Math.min(Math.max(r, 0), 100); return { e: 100 - r, r }; }
// both finite
e = Math.min(Math.max(e, 0), 100);
r = Math.min(Math.max(r, 0), 100);
if (e + r === 0) return { e: 50, r: 50 };
if (e + r === 100) return { e, r };
// scale to sum 100 to preserve proportion
const sum = e + r;
return { e: (e / sum) * 100, r: (r / sum) * 100 };
}
const { e: ePct, r: rPct } = normalizeSplit(extra_cash_emergency_pct, extra_cash_retirement_pct);
try {
// see if profile exists
const [existingRows] = await pool.query(`

View File

@ -25,28 +25,16 @@ const nav = useNavigate();
async function remove(row) {
if (!window.confirm('Delete this career profile?')) return;
try {
const r = await apiFetch(`/api/premium/career-profile/by-fields`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
scenario_title: row.scenario_title || null,
career_name : row.career_name || null,
start_date : row.start_date || null
})
const r = await apiFetch(`/api/premium/career-profile/${encodeURIComponent(row.id)}`, {
method: 'DELETE'
});
if (!r.ok) {
// 401/403 will already be handled by apiFetch
// 401/403 handled by apiFetch
const msg = await r.text().catch(() => 'Failed to delete');
alert(msg || 'Failed to delete');
return;
}
setRows(prev => prev.filter(x =>
!(
(x.scenario_title || '') === (row.scenario_title || '') &&
(x.career_name || '') === (row.career_name || '') &&
(x.start_date || '') === (row.start_date || '')
)
));
setRows(prev => prev.filter(x => x.id !== row.id));
} catch (e) {
console.error('Delete failed:', e);
alert('Failed to delete');

View File

@ -69,8 +69,8 @@ const FinancialOnboarding = ({ nextStep, prevStep, data, setData }) => {
}));
saveDraft({
financialData: {
extra_cash_emergency_pct: val,
extra_cash_retirement_pct: 100 - val
extra_cash_retirement_pct: val,
extra_cash_emergency_pct: 100 - val
}
}).catch(() => {});
} else {
@ -82,16 +82,36 @@ const FinancialOnboarding = ({ nextStep, prevStep, data, setData }) => {
extra_cash_retirement_pct: Number.isFinite(extra_cash_retirement_pct) ? extra_cash_retirement_pct : 50
}
}).catch(()=>{});
setData(prev => ({ ...prev, [name]: val }));
// Persist with 50/50 fallback if split is invalid or both 0
let ePct = Number(extra_cash_emergency_pct);
let rPct = Number(extra_cash_retirement_pct);
if (!Number.isFinite(ePct)) ePct = 0;
if (!Number.isFinite(rPct)) rPct = 0;
if ((ePct + rPct) === 0) { ePct = 50; rPct = 50; }
saveDraft({ financialData: {
[name]: val,
extra_cash_emergency_pct: ePct,
extra_cash_retirement_pct: rPct
}}).catch(()=>{});
}
};
const handleSubmit = () => {
// Final guard: coerce to numbers, clamp, and 50/50 if both resolve to 0
let ePct = Number(extra_cash_emergency_pct);
let rPct = Number(extra_cash_retirement_pct);
if (!Number.isFinite(ePct)) ePct = 0;
if (!Number.isFinite(rPct)) rPct = 0;
ePct = Math.min(Math.max(ePct, 0), 100);
rPct = Math.min(Math.max(rPct, 0), 100);
if ((ePct + rPct) === 0) { ePct = 50; rPct = 50; }
saveDraft({ financialData: {
extra_cash_emergency_pct: Number.isFinite(extra_cash_emergency_pct) ? extra_cash_emergency_pct : 50,
extra_cash_retirement_pct: Number.isFinite(extra_cash_retirement_pct) ? extra_cash_retirement_pct : 50
extra_cash_emergency_pct: ePct,
extra_cash_retirement_pct: rPct
}}).catch(()=>{});
nextStep();
};
};
return (
<div className="max-w-md mx-auto p-6 space-y-6">
@ -269,7 +289,7 @@ const FinancialOnboarding = ({ nextStep, prevStep, data, setData }) => {
value={extra_cash_emergency_pct}
onChange={handleChange}
onBlur={(e) => {
const v = parseFloat(e.target.value) || 0;
const v = parseFloat(e.target.value) || 50;
saveDraft({ financialData: { extra_cash_emergency_pct: v } }).catch(() => {});
}}
className="w-full border rounded p-2"
@ -285,7 +305,7 @@ const FinancialOnboarding = ({ nextStep, prevStep, data, setData }) => {
value={extra_cash_retirement_pct}
onChange={handleChange}
onBlur={(e) => {
const v = parseFloat(e.target.value) || 0;
const v = parseFloat(e.target.value) || 50;
saveDraft({ financialData: { extra_cash_retirement_pct: v } }).catch(() => {});
}}
className="w-full border rounded p-2"