Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const ResumeRoastLanding = lazy(() => import('./pages/features/ResumeRoastLandin
const GithubPortfolioLanding = lazy(() => import('./pages/features/GithubPortfolioLanding'));
const ProjectVisualizerLanding = lazy(() => import('./pages/features/ProjectVisualizerLanding'));
const JobFinderLanding = lazy(() => import('./pages/features/JobFinderLanding'));
const MockInterviewLanding = lazy(() => import('./pages/features/MockInterviewLanding'));
const MockInterviewLanding = lazy(() => import('./pages/features/MockInterviewForge'));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The route now lazy-loads the Forge implementation, but that module currently depends on ForgeFeaturePage, which imports subcomponents using ./forge/... paths that do not exist from its directory. As soon as /mock-interview is loaded, this can fail module resolution and break the page load. Either switch back to the stable landing component or fix the ForgeFeaturePage import paths before wiring this route to MockInterviewForge. [import error]

Severity Level: Critical 🚨
- ❌ /mock-interview landing fails; Forge page cannot render.
- ❌ Frontend build fails resolving ./forge subcomponent imports.
- ⚠️ Legacy /ai-interview redirect hits broken mock-interview route.
Steps of Reproduction ✅
1. Start the CareerPilot frontend with this PR applied so that `frontend/src/App.jsx`
defines `MockInterviewLanding` at line 111 as `lazy(() =>
import('./pages/features/MockInterviewForge'))` and registers the public `/mock-interview`
route at `frontend/src/App.jsx:285` using `<MockInterviewLanding />` inside `AppRoutes`.

2. Navigate to `http://localhost:PORT/mock-interview` in the browser, which causes React
Router to lazy-load the `MockInterviewLanding` chunk (the component imported from
`frontend/src/pages/features/MockInterviewForge.jsx:3-4`).

3. The `MockInterviewForge` component at
`frontend/src/pages/features/MockInterviewForge.jsx:3-4` immediately renders
`<ForgeFeaturePage slug="mock-interview" />`, pulling in
`frontend/src/components/forge/ForgeFeaturePage.jsx`.

4. When the bundler evaluates `ForgeFeaturePage.jsx`, it tries to resolve the imports at
`frontend/src/components/forge/ForgeFeaturePage.jsx:7-10` (`import StatusBadge from
'./forge/StatusBadge';`, `import MetricChip from './forge/MetricChip';`, `import
ForgeButton from './forge/ForgeButton';`, `import BentoCard from './forge/BentoCard';`),
but `LS /workspace/career-pilot/frontend/src/components/forge` shows only
`StatusBadge.jsx`, `MetricChip.jsx`, `ForgeButton.jsx`, and `BentoCard.jsx` in that
directory with no `forge/` subfolder, so the build/runtime produces a “Module not found:
Can't resolve './forge/StatusBadge'” style error and the `/mock-interview` page chunk
fails to load, breaking the route.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/App.jsx
**Line:** 111:111
**Comment:**
	*Import Error: The route now lazy-loads the Forge implementation, but that module currently depends on `ForgeFeaturePage`, which imports subcomponents using `./forge/...` paths that do not exist from its directory. As soon as `/mock-interview` is loaded, this can fail module resolution and break the page load. Either switch back to the stable landing component or fix the `ForgeFeaturePage` import paths before wiring this route to `MockInterviewForge`.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

const RecruitersLanding = lazy(() => import('./pages/features/RecruitersLanding'));

import ScrollToTop from "./components/ScrollToTop";
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/components/forge/BentoCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

/**
* Hover-glow bento card. Tracks cursor for the radial glow (forge signature).
*/
export default function BentoCard({ icon: Icon, title, description, className = '' }) {
const onMove = (e) => {
const r = e.currentTarget.getBoundingClientRect();
e.currentTarget.style.setProperty('--mx', `${e.clientX - r.left}px`);
e.currentTarget.style.setProperty('--my', `${e.clientY - r.top}px`);
};
return (
<div className={`forge-card ${className}`} onMouseMove={onMove}>
{Icon && (
<div className="ico">
<Icon size={22} strokeWidth={1.8} />
</div>
)}
<h3>{title}</h3>
<p>{description}</p>
</div>
);
}
9 changes: 9 additions & 0 deletions frontend/src/components/forge/ForgeButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { Link } from 'react-router-dom';

/** Forge button — renders as router Link or anchor. */
export default function ForgeButton({ to, href, children, variant = 'primary', ...rest }) {
const cls = `forge-btn ${variant === 'primary' ? 'forge-btn-primary' : 'forge-btn-ghost'}`;
if (to) return <Link to={to} className={cls} {...rest}>{children}</Link>;
return <a href={href || '#'} className={cls} {...rest}>{children}</a>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Using a raw anchor for the href branch causes full document reloads for internal app URLs (for example /login), which drops SPA state and bypasses React Router navigation behavior. Treat internal hrefs as router navigation (or require to for internal routes) so in-app transitions stay client-side. [performance]

Severity Level: Major ⚠️
- ⚠️ Forge sign-in button triggers full-page reload to /login.
- ⚠️ SPA state resets when clicking internal Forge CTA links.
Steps of Reproduction ✅
1. Ensure you are logged out so `useAuth()` in `ForgeFeaturePage` returns `user = null`
(see `frontend/src/components/forge/ForgeFeaturePage.jsx:51` where `{ user } = useAuth()`
is read).

2. Navigate to the public `/mock-interview` landing route, which is registered in
`AppRoutes` at `frontend/src/App.jsx:26-27` as `<Route path="/mock-interview"
element={<Suspense ...><MockInterviewLanding /></Suspense>} />` and backed by
`MockInterviewLanding` from `frontend/src/App.jsx:111` importing
`./pages/features/MockInterviewForge`.

3. On the rendered Forge landing, observe the sign-in CTA rendered by `ForgeFeaturePage`
at `frontend/src/components/forge/ForgeFeaturePage.jsx:72-74`, where `!user &&amp
<ForgeButton href="/login" variant="ghost">Sign in</ForgeButton>` is used, passing an
internal URL `/login` via the `href` prop.

4. The `ForgeButton` implementation at `frontend/src/components/forge/ForgeButton.jsx:5-8`
returns a React Router `<Link>` when `to` is provided but falls back to `<a href={href ||
'#'} ...>` when only `href` is set; clicking the “Sign in” button therefore performs a
full document navigation to `/login` (reloading the page and resetting SPA state) instead
of a client-side route transition via `<Link>`, causing unnecessary reloads and loss of
in-memory context during internal navigation.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeButton.jsx
**Line:** 8:8
**Comment:**
	*Performance: Using a raw anchor for the `href` branch causes full document reloads for internal app URLs (for example `/login`), which drops SPA state and bypasses React Router navigation behavior. Treat internal hrefs as router navigation (or require `to` for internal routes) so in-app transitions stay client-side.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

}
166 changes: 166 additions & 0 deletions frontend/src/components/forge/ForgeFeaturePage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
import { FEATURES_BY_SLUG } from '../../data/featuresConfig';
import Seo from '../../components/Seo';
import '../styles/forge.css';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This relative CSS import points to a non-existent components/styles directory from this file location, so the module cannot be resolved at build/runtime. Update the path to the actual src/styles/forge.css location. [import error]

Severity Level: Critical 🚨
- ❌ Forge feature routes fail to compile due to CSS.
- ❌ /mock-interview Forge landing cannot load at all.
- ⚠️ Future ForgeFeaturePage usages blocked until import fixed.
Steps of Reproduction ✅
1. Open frontend/src/pages/features/MockInterviewForge.jsx, which imports ForgeFeaturePage
from '../../components/forge/ForgeFeaturePage at lines 2-4 and is itself lazily imported
as MockInterviewLanding in frontend/src/App.jsx at line 111.

2. Inspect frontend/src/components/forge/ForgeFeaturePage.jsx where the ForgeFeaturePage
component is defined; line 6 imports '../styles/forge.css'.

3. From the ForgeFeaturePage.jsx location (frontend/src/components/forge), the relative
import '../styles/forge.css' resolves to frontend/src/components/styles/forge.css.

4. LS output for frontend/src/styles shows forge.css lives at
frontend/src/styles/forge.css and LS for frontend/src/components shows no styles
directory, so any build that compiles ForgeFeaturePage (e.g., when loading the
/mock-interview feature route) will fail with a module-not-found error for
'../styles/forge.css'.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 6:6
**Comment:**
	*Import Error: This relative CSS import points to a non-existent `components/styles` directory from this file location, so the module cannot be resolved at build/runtime. Update the path to the actual `src/styles/forge.css` location.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

import StatusBadge from './forge/StatusBadge';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This import adds an extra forge/ segment even though StatusBadge is in the same directory, so bundling fails with a missing module error. Import directly from the sibling file path. [import error]

Severity Level: Critical 🚨
- ❌ All ForgeFeaturePage-based routes crash on import error.
- ❌ /mock-interview Forge landing unusable in production.
- ⚠️ StatusBadge component cannot be reused in Forge page.
Steps of Reproduction ✅
1. Inspect frontend/src/pages/features/MockInterviewForge.jsx where MockInterviewForge
returns ForgeFeaturePage with slug "mock-interview" (lines 2-4); this page is wired into
AppRoutes via the lazy import MockInterviewLanding in frontend/src/App.jsx at line 111.

2. In frontend/src/components/forge/ForgeFeaturePage.jsx, note line 7 imports StatusBadge
from './forge/StatusBadge'.

3. From the directory frontend/src/components/forge, the path './forge/StatusBadge'
resolves to frontend/src/components/forge/forge/StatusBadge.jsx.

4. LS output for frontend/src/components/forge shows only BentoCard.jsx, ForgeButton.jsx,
ForgeFeaturePage.jsx, MetricChip.jsx, and StatusBadge.jsx at the top level, with no forge
subdirectory, so bundling ForgeFeaturePage for any feature route (mock-interview,
resume-builder, project-visualizer, resume-roast, github-portfolio via the imports found
by Grep) will throw a "Module not found: './forge/StatusBadge'" error.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 7:7
**Comment:**
	*Import Error: This import adds an extra `forge/` segment even though `StatusBadge` is in the same directory, so bundling fails with a missing module error. Import directly from the sibling file path.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

import MetricChip from './forge/MetricChip';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This relative import points to components/forge/forge/MetricChip, which does not exist, causing a hard import failure. Change it to the correct same-folder path. [import error]

Severity Level: Critical 🚨
- ❌ Forge feature heroes cannot render metric chips.
- ❌ Multiple feature landing pages fail during compilation.
- ⚠️ Stats display broken, degrading feature marketing UX.
Steps of Reproduction ✅
1. From Grep results, confirm ForgeFeaturePage is imported by multiple feature pages
(frontend/src/pages/features/ResumeBuilderForge.jsx, ProjectVisualizerForge.jsx,
ResumeRoastForge.jsx, MockInterviewForge.jsx, GithubPortfolioForge.jsx), so it is on
several landing routes.

2. Open frontend/src/components/forge/ForgeFeaturePage.jsx and observe line 8 importing
MetricChip from './forge/MetricChip'.

3. From the file’s directory frontend/src/components/forge, the './forge/MetricChip' path
resolves to frontend/src/components/forge/forge/MetricChip.jsx.

4. LS output for frontend/src/components/forge shows MetricChip.jsx exists as a sibling in
that directory, with no forge subfolder, so when the bundler compiles ForgeFeaturePage for
any of the Forge feature routes it will fail with "Module not found: './forge/MetricChip'"
and prevent those pages from loading.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 8:8
**Comment:**
	*Import Error: This relative import points to `components/forge/forge/MetricChip`, which does not exist, causing a hard import failure. Change it to the correct same-folder path.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

import ForgeButton from './forge/ForgeButton';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This import incorrectly references a forge subfolder under the current forge directory, so the file cannot be found. Point it to the sibling ForgeButton file. [import error]

Severity Level: Critical 🚨
- ❌ Primary CTA buttons on Forge features fail to render.
- ❌ Build may halt due to missing ForgeButton module.
- ⚠️ User onboarding flows via Forge landings disrupted.
Steps of Reproduction ✅
1. Verify via LS that frontend/src/components/forge contains ForgeButton.jsx as a sibling
file, with no nested forge directory.

2. In frontend/src/components/forge/ForgeFeaturePage.jsx, note line 9 imports ForgeButton
from './forge/ForgeButton'.

3. From the ForgeFeaturePage.jsx location (frontend/src/components/forge),
'./forge/ForgeButton' resolves to a non-existent path
frontend/src/components/forge/forge/ForgeButton.jsx.

4. During bundling of ForgeFeaturePage (invoked by feature pages such as
MockInterviewForge.jsx and others listed by Grep), module resolution for
'./forge/ForgeButton' will fail, breaking primary and secondary CTA buttons on all Forge
feature landings and potentially stopping the build.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 9:9
**Comment:**
	*Import Error: This import incorrectly references a `forge` subfolder under the current `forge` directory, so the file cannot be found. Point it to the sibling `ForgeButton` file.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

import BentoCard from './forge/BentoCard';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This import path is incorrect for a sibling component and resolves to a non-existent location, which will break compilation. Use the direct local path to BentoCard. [import error]

Severity Level: Critical 🚨
- ❌ Forge capabilities bento grid cannot render at all.
- ❌ All ForgeFeaturePage landings risk build-time failure.
- ⚠️ Feature demos and showcases unavailable to end users.
Steps of Reproduction ✅
1. Confirm via BulkRead that BentoCard.jsx is defined in
frontend/src/components/forge/BentoCard.jsx, exporting the BentoCard component (lines
3-23).

2. In frontend/src/components/forge/ForgeFeaturePage.jsx, line 10 imports BentoCard from
'./forge/BentoCard'.

3. Given ForgeFeaturePage.jsx resides in frontend/src/components/forge, the
'./forge/BentoCard' import resolves to frontend/src/components/forge/forge/BentoCard.jsx,
which does not exist per LS output.

4. When ForgeFeaturePage is compiled for any feature route (ResumeBuilderForge,
ProjectVisualizerForge, ResumeRoastForge, GithubPortfolioForge, MockInterviewForge), the
bundler will raise a module-not-found error for './forge/BentoCard', breaking the
capabilities bento section and potentially failing the entire build.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 10:10
**Comment:**
	*Import Error: This import path is incorrect for a sibling component and resolves to a non-existent location, which will break compilation. Use the direct local path to `BentoCard`.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎


const ICONS = {
FileText: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6',
Type: 'M4 7V4h16v3 M9 20h6 M12 4v16',
Github: 'M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22',
Sparkles: 'M12 3v3 M12 18v3 M3 12h3 M18 12h3 M5.6 5.6l2.1 2.1 M16.3 16.3l2.1 2.1 M18.4 5.6l-2.1 2.1 M7.7 16.3l-2.1 2.1',
BarChart: 'M3 3v18h18 M8 17V9 M13 17V5 M18 17v-6',
Layout: 'M3 3h18v18H3z M3 9h18 M9 21V9',
Linkedin: 'M4 4a2 2 0 1 0 0 4 2 2 0 0 0 0-4z M4 9h4v11H4z M10 9h4v3a4 4 0 0 1 8 0v8h-4v-7a2 2 0 0 0-4 0v7h-4z',
Download: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3',
Mic: 'M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z M19 10v2a7 7 0 0 1-14 0v-2 M12 19v4 M8 23h8',
Briefcase: 'M2 7h20v13H2z M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16',
Flame: 'M12 2s4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-3-2 1-4 3-4 6a7 7 0 0 0 14 0c0-5-7-11-7-11z',
Network: 'M12 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M5 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M19 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M7 18l3-7 M17 18l-3-7 M8 19h8',
Users: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75',
Palette: 'M12 2a9 9 0 0 0 0 18c1.1 0 2-.9 2-2 0-.5-.2-1-.5-1.3-.3-.4-.5-.8-.5-1.2 0-1 .8-1.8 1.8-1.8H17a4 4 0 0 0 4-4c0-4.4-4-8-9-8z M7.5 11.5A1 1 0 1 0 7 13a1 1 0 0 0 .5-1.5z M12 7.5A1 1 0 1 0 12.5 9 1 1 0 0 0 12 7.5z',
Zap: 'M13 2L3 14h9l-1 8 10-12h-9z',
Smartphone: 'M7 2h10a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z M12 18h.01',
Globe: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z M2 12h20 M12 2a15 15 0 0 1 0 20 M12 2a15 15 0 0 0 0 20',
};

function Icon({ name, size = 22, strokeWidth = 1.8 }) {
const d = ICONS[name];
if (!d) return null;
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
{d.split(' M').map((seg, i) => (
<path key={i} d={(i === 0 ? seg : 'M' + seg)} />
))}
</svg>
);
}

/**
* ForgeFeaturePage — data-driven landing for a single feature route.
* Reads the existing FEATURES_BY_SLUG[slug] config and renders a cohesive,
* forge-ai-inspired page (status chips, monospace metrics, bento showcase, steps).
* Each route landing imports this with its slug.
*/
export default function ForgeFeaturePage({ slug }) {
const { user } = useAuth();
const config = FEATURES_BY_SLUG[slug];
if (!config) return <div className="forge-page">Unknown feature: {slug}</div>;

const heroCtaText = user ? config.primaryAction.label : config.hero.primaryCta.text;
const heroCtaLink = user ? config.primaryAction.to : config.hero.primaryCta.to;
const ctaText = user ? config.primaryAction.label : config.cta.ctaText;
const ctaLink = user ? config.primaryAction.to : config.cta.ctaTo;

return (
<div className="forge-page">
<Seo {...config.seo} />

<nav className="forge-nav">
<Link to="/" className="forge-brand">CareerPilot<span className="dot">.</span></Link>
<div className="forge-nav-links">
<Link to="/resume-builder" className="forge-nav-link">Resume Builder</Link>
<Link to="/portfolio-builder" className="forge-nav-link">Portfolio</Link>
<Link to="/job-finder" className="forge-nav-link">Job Finder</Link>
<Link to="/mock-interview" className="forge-nav-link">Mock Interview</Link>
</div>
<div className="forge-nav-actions">
{!user && <ForgeButton href="/login" variant="ghost">Sign in</ForgeButton>}
<ForgeButton to={heroCtaLink} variant="primary">{user ? 'Dashboard' : 'Get started for free'}</ForgeButton>
</div>
</nav>

{/* HERO */}
<section className="forge-section forge-container forge-hero">
<StatusBadge label="OPERATIONAL" />
<h1>
{config.hero.title} <span className="accent">{config.hero.accentText}</span>
</h1>
<p>{config.hero.description}</p>
<div className="forge-hero-actions">
<ForgeButton to={heroCtaLink} variant="primary">{heroCtaText}</ForgeButton>
{config.hero.secondaryCta && (
<ForgeButton href={config.hero.secondaryCta.href} variant="ghost">{config.hero.secondaryCta.text}</ForgeButton>
)}
</div>
<div className="forge-metrics">
{config.hero.stats.map((s, i) => (
<MetricChip key={i} value={s.value} label={s.label} accent={i === 0} />
))}
</div>
</section>

{/* SHOWCASE */}
{config.showcase && (
<section className="forge-section forge-container" id="demo">
<div style={{ textAlign: 'center' }}>
<span className="forge-label">Capabilities</span>
<h2 className="forge-h2">{config.showcase.heading}</h2>
</div>
<div className="forge-bento">
{config.showcase.features.map((f, i) => (
<BentoCard key={i} icon={(p) => <Icon name={f.icon} {...p} />} title={f.title} description={f.description} />
))}
</div>
</section>
)}

{/* HOW IT WORKS */}
{config.howItWorks && (
<section className="forge-section forge-container">
<div style={{ textAlign: 'center' }}>
<span className="forge-label">Workflow</span>
<h2 className="forge-h2">{config.howItWorks.title}</h2>
</div>
<div className="forge-steps">
{config.howItWorks.steps.map((s, i) => (
<div key={i} className="forge-step">
<span className="n">STEP {s.number}</span>
<h4>{s.title}</h4>
<p>{s.description}</p>
</div>
))}
</div>
</section>
)}

{/* TESTIMONIALS */}
{config.testimonials && config.testimonials.items?.length > 0 && (
<section className="forge-section forge-container">
<div style={{ textAlign: 'center' }}>
<span className="forge-label">Signal</span>
<h2 className="forge-h2">{config.testimonials.heading}</h2>
</div>
{config.testimonials.items.map((t, i) => (
<div key={i} className="forge-quote">
<p className="q">“{t.quote}”</p>
<div className="who">
{t.avatar && <img src={t.avatar} alt="" width="36" height="36" style={{ borderRadius: '50%' }} />}
<span><strong style={{ color: 'var(--forge-text)' }}>{t.name}</strong> · {t.role}{t.company ? ` @ ${t.company}` : ''}</span>
<span className="metric" style={{ marginLeft: 'auto' }}>{t.metric}</span>
</div>
</div>
))}
</section>
)}

{/* CTA */}
<section className="forge-container">
<div className="forge-cta">
<h2>{config.cta.headline}</h2>
<p>{config.cta.subtext}</p>
<ForgeButton to={ctaLink} variant="primary">{ctaText}</ForgeButton>
</div>
</section>

<footer className="forge-foot">
CareerPilot · {config.name} · built with the Forge design system
</footer>
</div>
);
}
11 changes: 11 additions & 0 deletions frontend/src/components/forge/MetricChip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

/** Monospace metric chip used in hero stat rows. */
export default function MetricChip({ value, label, accent = false }) {
return (
<div className="forge-metric">
<div className={`v ${accent ? 'accent' : ''}`}>{value}</div>
<div className="l">{label}</div>
</div>
);
}
15 changes: 15 additions & 0 deletions frontend/src/components/forge/StatusBadge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

/**
* Forge signature status chip — operational/SLA style pill.
* variant: 'ok' | 'warn' | 'danger'
*/
export default function StatusBadge({ label = 'OPERATIONAL', variant = 'ok', className = '' }) {
const v = variant === 'danger' ? 'danger' : variant === 'warn' ? 'warn' : 'ok';
return (
<span className={`forge-status ${v} ${className}`}>
<span className="pulse" />
{label}
</span>
);
}
80 changes: 80 additions & 0 deletions frontend/src/components/landing/ForgeToolsSection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { motion } from 'framer-motion';
import { FEATURES } from '../../data/featuresConfig';
import '../styles/forge.css';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This stylesheet import resolves to src/components/styles/forge.css from the current directory, but the stylesheet lives under src/styles, so the import fails. Correct the relative path to the real stylesheet location. [import error]

Severity Level: Major ⚠️
- ⚠️ Latent import error in ForgeToolsSection landing component.
- ⚠️ Future "Powerful AI tools" landing could crash.
- ⚠️ Design system reuse hindered for new tools grid.
Steps of Reproduction ✅
1. Grep for ForgeToolsSection shows only its definition in
frontend/src/components/landing/ForgeToolsSection.jsx:25, indicating the component is not
yet wired into routes but is intended as a landing grid.

2. In frontend/src/components/landing/ForgeToolsSection.jsx, line 4 imports
'../styles/forge.css'.

3. From the ForgeToolsSection.jsx directory (frontend/src/components/landing), the path
'../styles/forge.css' resolves to frontend/src/components/styles/forge.css.

4. LS output for frontend/src/styles confirms forge.css exists at
frontend/src/styles/forge.css, while LS for frontend/src/components shows no styles
directory, so when ForgeToolsSection is imported into a page like Home.jsx or another
landing, any build including that component will fail with a module-not-found error for
'../styles/forge.css'.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** frontend/src/components/landing/ForgeToolsSection.jsx
**Line:** 4:4
**Comment:**
	*Import Error: This stylesheet import resolves to `src/components/styles/forge.css` from the current directory, but the stylesheet lives under `src/styles`, so the import fails. Correct the relative path to the real stylesheet location.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

import StatusBadge from '../forge/StatusBadge';
import ForgeButton from '../forge/ForgeButton';

const ICON_PATHS = {
FileText: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6',
Palette: 'M12 2a9 9 0 0 0 0 18c1.1 0 2-.9 2-2 0-.5-.2-1-.5-1.3-.3-.4-.5-.8-.5-1.2 0-1 .8-1.8 1.8-1.8H17a4 4 0 0 0 4-4c0-4.4-4-8-9-8z M7.5 11.5A1 1 0 1 0 7 13a1 1 0 0 0 .5-1.5z M12 7.5A1 1 0 1 0 12.5 9 1 1 0 0 0 12 7.5z',
Flame: 'M12 2s4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-3-2 1-4 3-4 6a7 7 0 0 0 14 0c0-5-7-11-7-11z',
Github: 'M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22',
Network: 'M12 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M5 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M19 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M7 18l3-7 M17 18l-3-7 M8 19h8',
Mic: 'M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z M19 10v2a7 7 0 0 1-14 0v-2 M12 19v4 M8 23h8',
Users: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75',
Briefcase: 'M2 7h20v13H2z M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16',
};

const header = { hidden: {}, show: { transition: { staggerChildren: 0.12 } } };
const item = {
hidden: { opacity: 0, y: 24 },
show: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] } },
};

export default function ForgeToolsSection() {
return (
<section className="forge-page" style={{ padding: '84px 0' }}>
<div className="forge-container">
<motion.div
variants={header}
initial="hidden"
whileInView="show"
viewport={{ once: true, margin: '-100px' }}
style={{ textAlign: 'center' }}
>
<motion.div variants={item} style={{ display: 'flex', justifyContent: 'center', marginBottom: 18 }}>
<StatusBadge label="ALL SYSTEMS OPERATIONAL" />
</motion.div>
<motion.h2 variants={item} className="forge-h2">
Powerful AI tools for <span style={{ color: 'var(--forge-accent)' }}>every step</span>
</motion.h2>
<motion.p variants={item} className="forge-sub">
From your first resume draft to your final interview, CareerPilot gives you the unfair advantage you need.
</motion.p>
</motion.div>

<div className="forge-tools-grid" style={{ marginTop: 44 }}>
{FEATURES.map((f, i) => {
const Icon = (p) => (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8} strokeLinecap="round" strokeLinejoin="round" {...p}>
{(ICON_PATHS[f.icon?.name] || ICON_PATHS.FileText).split(' M').map((seg, k) => (
<path key={k} d={k === 0 ? seg : 'M' + seg} />
))}
</svg>
);
const large = f.size === 'large';
return (
<motion.div
key={f.slug}
variants={item}
className={`forge-tool ${large ? 'lg' : ''}`}
style={large ? { display: 'flex', flexDirection: 'column', justifyContent: 'space-between' } : {}}
>
<div className="ico"><Icon /></div>
<div>
<span className="badge-tag">{f.badge || 'Tool'}</span>
<h3>{f.name}</h3>
<p>{f.tagline}</p>
</div>
<div style={{ marginTop: 18 }}>
<ForgeButton to={f.primaryAction.to} variant="ghost">{f.primaryAction.label} →</ForgeButton>
</div>
</motion.div>
);
})}
</div>
</div>
</section>
);
}
5 changes: 5 additions & 0 deletions frontend/src/pages/features/GithubPortfolioForge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage';
export default function GithubPortfolioForge() {
return <ForgeFeaturePage slug="github-portfolio" />;
}
5 changes: 5 additions & 0 deletions frontend/src/pages/features/MockInterviewForge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage';
export default function MockInterviewForge() {
return <ForgeFeaturePage slug="mock-interview" />;
}
5 changes: 5 additions & 0 deletions frontend/src/pages/features/ProjectVisualizerForge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage';
export default function ProjectVisualizerForge() {
return <ForgeFeaturePage slug="project-visualizer" />;
}
5 changes: 5 additions & 0 deletions frontend/src/pages/features/ResumeBuilderForge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage';
export default function ResumeBuilderForge() {
return <ForgeFeaturePage slug="resume-builder" />;
}
5 changes: 5 additions & 0 deletions frontend/src/pages/features/ResumeRoastForge.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage';
export default function ResumeRoastForge() {
return <ForgeFeaturePage slug="resume-roast" />;
}
Loading
Loading