Updated pricing, financial disclaimer in retirement planner
This commit is contained in:
parent
00cedaf0dc
commit
6e45a4deca
@ -1 +1 @@
|
||||
960faad1696b81c0f004065ea713edaef64ab816-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b
|
||||
506c4d11372627a92e39ee44d85a809d000a0840-006fe5ea7fd8cb46290bcd0cf210f88f2ec04061-e9eccd451b778829eb2f2c9752c670b707e1268b
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,3 +27,4 @@ uploads/.env
|
||||
.env.*
|
||||
scan-env.sh
|
||||
.aptiva-test-user.json
|
||||
APTIVA_AI_FEATURES_DOCUMENTATION.md
|
||||
|
||||
@ -1 +1 @@
|
||||
98f674eca26e366aee0b41f250978982060105f0
|
||||
ad5628b638213a971abbea4f95362eca8672be7b
|
||||
|
||||
@ -1 +1 @@
|
||||
98f674eca26e366aee0b41f250978982060105f0
|
||||
ad5628b638213a971abbea4f95362eca8672be7b
|
||||
|
||||
@ -1747,7 +1747,7 @@ app.post('/api/chat/threads', authenticateUser, async (req, res) => {
|
||||
);
|
||||
// Seed a first assistant message so the drawer never appears blank
|
||||
const intro =
|
||||
'Hi — Aptiva Support here. I can help with CareerExplorer, account/billing, or technical issues. What do you need?';
|
||||
'Hi — Aptiva Support here. I can help with how to use AptivaAI, account/billing, or technical issues. What do you need?';
|
||||
await pool.query(
|
||||
'INSERT INTO ai_chat_messages (thread_id,user_id,role,content) VALUES (?,?, "assistant", ?)',
|
||||
[id, userId, intro]
|
||||
|
||||
@ -94,7 +94,8 @@ http {
|
||||
return 302 /signin$is_args$args;
|
||||
}
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
# First try the exact file, then directory with index.html, then directory/, then fallback
|
||||
try_files $uri $uri/index.html $uri/ /index.html;
|
||||
}
|
||||
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg)$ {
|
||||
expires 6M;
|
||||
|
||||
1043
package-lock.json
generated
1043
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@ -73,10 +73,29 @@
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"start": "react-scripts start --host 0.0.0.0",
|
||||
"build": "react-scripts build",
|
||||
"build": "react-scripts build && react-snap",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"reactSnap": {
|
||||
"include": [
|
||||
"/signin",
|
||||
"/signup",
|
||||
"/forgot-password",
|
||||
"/privacy",
|
||||
"/terms"
|
||||
],
|
||||
"skipThirdPartyRequests": true,
|
||||
"cacheAjaxRequests": false,
|
||||
"puppeteerArgs": [
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox"
|
||||
],
|
||||
"minifyHtml": {
|
||||
"collapseWhitespace": true,
|
||||
"removeComments": true
|
||||
}
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
@ -117,6 +136,7 @@
|
||||
"glob": "^11.0.3",
|
||||
"globals": "^16.3.0",
|
||||
"postcss": "^8.5.3",
|
||||
"react-snap": "^1.23.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript-eslint": "^8.38.0"
|
||||
}
|
||||
|
||||
@ -90,45 +90,69 @@ export default function Paywall() {
|
||||
|
||||
// No active sub => pricing
|
||||
return (
|
||||
<div className="max-w-lg mx-auto p-6 space-y-8">
|
||||
<header className="text-center">
|
||||
<h2 className="text-2xl font-semibold">Upgrade to AptivaAI</h2>
|
||||
<p className="text-sm text-gray-600">Choose the plan that fits your needs – cancel anytime.</p>
|
||||
<div className="max-w-lg mx-auto p-6 space-y-6">
|
||||
<header className="text-center space-y-2">
|
||||
<h2 className="text-2xl font-semibold">Upgrade to Premium</h2>
|
||||
<p className="text-sm text-gray-600">Unlock AI-enhanced career planning and financial projections</p>
|
||||
</header>
|
||||
|
||||
{/* Premium */}
|
||||
<section className="border rounded-lg p-4 space-y-4">
|
||||
<h3 className="text-lg font-medium">Premium</h3>
|
||||
<ul className="text-sm list-disc list-inside space-y-1">
|
||||
<li>Career milestone planning</li>
|
||||
<li>Financial projections & benchmarks</li>
|
||||
<li>2 × resume optimizations / week</li>
|
||||
{/* Single Premium Tier */}
|
||||
<section className="border-2 border-aptiva rounded-xl p-6 space-y-4 bg-gradient-to-br from-white to-blue-50">
|
||||
<div className="text-center">
|
||||
<h3 className="text-xl font-semibold text-aptiva">AptivaAI Premium</h3>
|
||||
<p className="text-xs text-gray-600 mt-1">Everything you need for career planning</p>
|
||||
</div>
|
||||
|
||||
<ul className="text-sm space-y-2">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-600 font-bold mt-0.5">✓</span>
|
||||
<span><strong>AI Career Coach</strong> – Unlimited conversations with personalized guidance</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-600 font-bold mt-0.5">✓</span>
|
||||
<span><strong>Career Roadmap</strong> – Milestone tracking with financial impact modeling</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-600 font-bold mt-0.5">✓</span>
|
||||
<span><strong>20-Year Financial Projections</strong> – Model multiple career scenarios</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-600 font-bold mt-0.5">✓</span>
|
||||
<span><strong>Resume Optimizer</strong> – 3 AI-enhanced optimizations per week</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-600 font-bold mt-0.5">✓</span>
|
||||
<span><strong>Retirement Planner</strong> – Beta access to retirement scenario modeling</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Button onClick={() => checkout('premium', 'monthly')}>$4.99 / mo</Button>
|
||||
<Button onClick={() => checkout('premium', 'annual')}>$49 / yr</Button>
|
||||
<div className="pt-4 space-y-3 flex flex-col items-center">
|
||||
<Button
|
||||
onClick={() => checkout('premium', 'monthly')}
|
||||
className="w-full max-w-xs h-12 text-base"
|
||||
size="lg"
|
||||
>
|
||||
$24 / month
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => checkout('premium', 'annual')}
|
||||
variant="outline"
|
||||
className="w-full max-w-xs h-14 text-base border-2 border-aptiva text-aptiva hover:bg-aptiva hover:text-white flex flex-col items-center justify-center"
|
||||
size="lg"
|
||||
>
|
||||
<span>$199 / year</span>
|
||||
<span className="text-xs font-normal mt-0.5">Save $89 – Best Value!</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-center text-gray-500 pt-2">Cancel anytime • No long-term commitment</p>
|
||||
</section>
|
||||
|
||||
{/* Pro */}
|
||||
<section className="border rounded-lg p-4 space-y-4">
|
||||
<h3 className="text-lg font-medium">Pro Premium</h3>
|
||||
<ul className="text-sm list-disc list-inside space-y-1">
|
||||
<li>Everything in Premium</li>
|
||||
<li>Priority GPT-4o usage & higher rate limits</li>
|
||||
<li>5 × resume optimizations / week</li>
|
||||
</ul>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Button onClick={() => checkout('pro', 'monthly')}>$7.99 / mo</Button>
|
||||
<Button onClick={() => checkout('pro', 'annual')}>$79 / yr</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Button variant="secondary" onClick={() => nav(-1)} className="w-full">
|
||||
Cancel / Go back
|
||||
</Button>
|
||||
<div className="flex justify-center">
|
||||
<Button variant="secondary" onClick={() => nav(-1)} className="w-full max-w-xs">
|
||||
Maybe later
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { Button } from './ui/button.js';
|
||||
import RetirementChatBar from './RetirementChatBar.js';
|
||||
import ScenarioDiffDrawer from './ScenarioDiffDrawer.js';
|
||||
import ChatCtx from '../contexts/ChatCtx.js';
|
||||
import FinancialDisclaimer from './FinancialDisclaimer.js';
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* tiny class‑name helper
|
||||
@ -133,9 +134,14 @@ export default function RetirementPlanner () {
|
||||
const baselineYears = simYearsMap[baselineId] ?? null; // renamed
|
||||
|
||||
return (
|
||||
<div className="flex flex-col md:flex-row h-full relative">
|
||||
{/* ================= MAIN COLUMN =========================== */}
|
||||
<main className="flex-1 p-4 overflow-y-auto">
|
||||
|
||||
<div className="flex flex-col md:flex-row h-full relative">
|
||||
{/* ================= MAIN COLUMN =========================== */}
|
||||
<main className="flex-1 p-4 overflow-y-auto">
|
||||
{/* Disclaimer spans above both columns */}
|
||||
<div className="mx-auto max-w-screen-lg mb-3">
|
||||
<FinancialDisclaimer />
|
||||
</div>
|
||||
{/* desktop add */}
|
||||
{!isMobile && (
|
||||
<Button onClick={handleAddScenario} className="mb-4">
|
||||
|
||||
15
src/index.js
15
src/index.js
@ -9,14 +9,23 @@ import { installStorageGuard } from './utils/storageGuard.js';
|
||||
|
||||
installStorageGuard(); // Initialize storage guard
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
const rootElement = document.getElementById('root');
|
||||
const appContent = (
|
||||
<BrowserRouter>
|
||||
<PageFlagsProvider>
|
||||
<App />
|
||||
</PageFlagsProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
);
|
||||
|
||||
// Use hydration if there's pre-rendered content (from react-snap)
|
||||
// Otherwise use normal rendering (development mode)
|
||||
if (rootElement.hasChildNodes()) {
|
||||
ReactDOM.hydrateRoot(rootElement, appContent);
|
||||
} else {
|
||||
const root = ReactDOM.createRoot(rootElement);
|
||||
root.render(appContent);
|
||||
}
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user