Skip to content

Feature import user cv#132

Open
badarouzia wants to merge 15 commits into
stagingfrom
feature-import-user-cv
Open

Feature import user cv#132
badarouzia wants to merge 15 commits into
stagingfrom
feature-import-user-cv

Conversation

@badarouzia
Copy link
Copy Markdown
Collaborator

@badarouzia badarouzia commented May 12, 2026

What type of PR is this? (check all applicable)

  • ✨ Feature
  • 🛑 Bug
  • ⚠️ Anomaly
  • 📝 Doc
  • 🎨 Style
  • 🧑‍💻 Refactor
  • 🛠️ Setup
  • 🏗️ Build
  • 🔥 Perfs
  • ✅ Test
  • 🔁 CI
  • ⏩ Revert

Description

This Pull Request introduces the Compatibility Analysis module. This feature allows users to bridge the gap between their current profile and a specific job offer by leveraging AI to extract skills and generate a tailored learning journey.

Features and Workflow

The module follows a structured three-step process as seen in the implemented UI:

Document and Data Intake

  • CV Upload: Drag-and-drop support for PDF and DOCX files with size validation.
  • Job Link Integration: Automated scraping of job descriptions via URL.
  • Deadline Tracking: A priority-based calendar system that calculates application urgency (Overdue, Today, or Days Left).

AI Processing

  • Visual progress feedback during Key Skills Extraction.
  • Matching logic between user experience and recruiter expectations.

Personalized Outcome

  • Confirmation screen displaying validated skills and optimized paths.
  • Direct CTA to Start My Training, leading the user to their customized curriculum.

Technical Changes

  • Component Architecture: Created CVAnalysisPage as a stateful orchestrator for UploaderCard, AIProcessingOverlay, and AnalysisResultCard.
  • Iconography: Migrated all hardcoded assets to the centralized iconMap system using react-icons.
  • State Management: Implemented hooks to handle file binary state, URL validation, and date calculations for the deadline urgency logic.
  • Styling: Built a responsive, clean grid layout using modern CSS-in-JS, ensuring a Premium AI feel.

Closes EpitechPromo2027/G-EIP-600-NAN-6-1-eip-tugdual.de-reviers#


Closes EpitechPromo2027/G-EIP-600-NAN-6-1-eip-tugdual.de-reviers#

Workspace

  • 🖥️ Web
  • 🛠️ Server
  • 🔁 CI
  • 🤖 Ai
  • 📱 App

Screenshots

Screenshot from 2026-05-10 08-54-29 Screenshot from 2026-05-12 11-14-48 Screenshot from 2026-05-12 11-15-11 Screenshot from 2026-05-12 11-15-17

@railway-app
Copy link
Copy Markdown

railway-app Bot commented May 12, 2026

This PR was not deployed automatically as @badarouzia does not have access to the Railway project.

In order to get automatic PR deploys, please add @badarouzia to your workspace on Railway.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
talk-up-ai-dev Ready Ready Preview, Comment May 20, 2026 9:33am

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a new CV Compatibility Analysis flow in the web app, adding a 3-step UI (upload → “AI processing” overlay → results) and introducing supporting UI atoms/molecules/organisms plus tests.

Changes:

  • Reworked /cv-analysis route into a stateful orchestration page for upload, processing overlay, and result display.
  • Added new CV-import UI components (UploaderCard, AIProcessingOverlay, AnalysisResultCard) plus supporting atoms/molecules and Vitest tests.
  • Performed minor formatting/normalization updates in shared styles and a JSON data file.

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
web/src/styles/tailwind.css Normalizes hex color casing for CSS variables.
web/src/styles/scrollbar.css Re-indents scrollbar CSS (no functional change).
web/src/styles/calendar.css Re-formats calendar override CSS (no functional change).
web/src/routes/cv-analysis.tsx New CV analysis workflow page and orchestration logic.
web/src/components/organisms/cv-import/UploaderCard.tsx Drag-and-drop CV upload UI + deadline input/urgency display.
web/src/components/organisms/cv-import/Uploadercard.spec.tsx Adds tests for UploaderCard behavior (upload + deadline).
web/src/components/organisms/cv-import/AnalysisResultCard.tsx Results/CTA card shown after analysis completion.
web/src/components/organisms/cv-import/Analysisresultcard.spec.tsx Adds tests for AnalysisResultCard behavior.
web/src/components/organisms/cv-import/AIProcessingOverlay.tsx Simulated analysis overlay with progress + rotating status messages.
web/src/components/molecules/cv-import/Stepper.tsx Stepper molecule for the multi-step flow.
web/src/components/molecules/cv-import/AnalysisStatus.tsx Spinner + status message molecule used by the overlay.
web/src/components/molecules/convincing-banner/reviews.json Re-indents JSON content (no semantic change).
web/src/components/atoms/cv-import/StepIndicator.tsx Atom for individual step display.
web/src/components/atoms/cv-import/ProgressBar.tsx Progress bar atom used by the overlay.
web/src/components/atoms/cv-import/FileBadge.tsx File extension badge atom used in the uploader UI.
Comments suppressed due to low confidence (4)

web/src/routes/cv-analysis.tsx:16

  • /cv-analysis is marked as requiresAuth: true in routes.config.ts, but this route no longer applies beforeLoad: createAuthGuard('/cv-analysis'). This makes the page accessible without the configured auth check. Re-add the auth guard (or update the route config if it’s intended to be public) so routing behavior matches the central config.
export const Route = createFileRoute('/cv-analysis')({
  component: CVAnalysisPage,
});

web/src/routes/cv-analysis.tsx:45

  • URL validation is currently jobUrl.trim().startsWith('http'), which can treat invalid strings as valid (e.g. httpxyz) and is duplicated in multiple places. Consider centralizing this into a single boolean (e.g. isJobUrlValid) and validating via new URL(jobUrl) with an allowed protocol list (http:/https:).
  const handleStartAnalysis = () => {
    if (cvFile && jobUrl.trim().startsWith('http')) {
      setIsAnalyzing(true);
    }
  };

web/src/routes/cv-analysis.tsx:85

  • onStartCourse currently logs to the console. Since this is a user-facing CTA, it should trigger real navigation/action (e.g. router.navigate to the generated curriculum route) or be removed until implemented; leaving console.log here can easily ship to production.
        <AnalysisResultCard
          onRetry={handleReset}
          onStartCourse={() => console.log('Navigating to course path...')}
        />

web/src/components/organisms/cv-import/UploaderCard.tsx:168

  • The UI states “Max size: 5 MB”, but there is no size/type validation before calling onFileSelect (both for drop and input). Add client-side checks (size limit + allowed MIME/types) and provide user feedback when the file is rejected, otherwise users can select larger/unsupported files despite the UI hint.
          <input
            id="cv-input"
            type="file"
            hidden
            accept=".pdf,.doc,.docx"
            onChange={(e) =>
              e.target.files?.[0] && onFileSelect(e.target.files[0])
            }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web/src/routes/cv-analysis.tsx
Comment thread web/src/components/organisms/cv-import/UploaderCard.tsx
Comment thread web/src/components/organisms/cv-import/Uploadercard.spec.tsx
Comment thread web/src/components/organisms/cv-import/AIProcessingOverlay.tsx Outdated
Comment thread web/src/components/organisms/cv-import/AIProcessingOverlay.tsx Outdated
Comment thread web/src/components/organisms/cv-import/AnalysisResultCard.tsx
Comment thread web/src/components/organisms/cv-import/AnalysisResultCard.tsx
Comment thread web/src/components/organisms/cv-import/Uploadercard.spec.tsx
Comment thread web/src/components/organisms/cv-import/Analysisresultcard.spec.tsx
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 11 comments.

Comments suppressed due to low confidence (8)

web/src/routes/cv-analysis.tsx:16

  • The route definition no longer applies beforeLoad: createAuthGuard(...). This makes /cv-analysis accessible without authentication and could expose CV-related UI to unauthenticated users. Re-add the auth guard (or explicitly document/handle why this route must be public).
export const Route = createFileRoute('/cv-analysis')({
  component: CVAnalysisPage,
});

web/src/routes/cv-analysis.tsx:85

  • onStartCourse currently just logs to the console. This leaves the primary CTA non-functional in production builds and makes it easy to miss navigation wiring. Consider using TanStack Router navigation (or pass a real callback from a parent) instead of console.log.
        <AnalysisResultCard
          onRetry={handleReset}
          onStartCourse={() => console.log('Navigating to course path...')}
        />

web/src/routes/cv-analysis.tsx:133

  • The job-offer URL <input> has no associated <label> or aria-label, so screen readers will only announce it generically (placeholder text is not a reliable accessible name). Add a visible label or at least an aria-label/aria-labelledby.
                  <input
                    type="url"
                    style={urlInputStyle}
                    placeholder="Paste LinkedIn, WTTJ link..."
                    value={jobUrl}
                    onChange={(e) => setJobUrl(e.target.value)}
                  />

web/src/routes/cv-analysis.tsx:174

  • This file uses many hardcoded colors and large inline style objects (e.g. pageContainer, jobCard, button colors) rather than the existing Tailwind + design-token approach used across routes. This makes theming and future design updates harder. Consider translating these styles to Tailwind classes and/or CSS variables (e.g. var(--color-...)).
/** @type {React.CSSProperties} Layout for the main page container */
const pageContainer: React.CSSProperties = {
  backgroundColor: '#F8FAFC',
  minHeight: '100vh',
  padding: '60px 20px',
  fontFamily: 'Inter, system-ui, sans-serif',
};

web/src/routes/cv-analysis.tsx:170

  • This file references React.CSSProperties but does not import React (or CSSProperties) for the React type namespace. In this codebase, other files import React when using React.* types (e.g. web/src/types/events.ts:1). Import type { CSSProperties } from react (or import React from 'react') to avoid TS/lint issues.
/** @type {React.CSSProperties} Layout for the main page container */
const pageContainer: React.CSSProperties = {
  backgroundColor: '#F8FAFC',

web/src/components/organisms/cv-import/AIProcessingOverlay.tsx:80

  • User-facing title text contains spelling/grammar errors: “Analys TalkUp.AI in processe”. This will be visible during the analysis overlay; please correct it (e.g., “TalkUp.AI analysis in progress”).
    <div style={overlayStyle}>
      <div style={contentBox}>
        <h2 style={{ marginBottom: '24px' }}>Analys TalkUp.AI in processe</h2>

        <AnalysisStatus message={currentMessage} />

web/src/components/organisms/cv-import/AIProcessingOverlay.tsx:103

  • This file uses React.CSSProperties for style objects but does not import React (or CSSProperties). To match existing code patterns and avoid TS/lint issues, import type { CSSProperties } from react (or import React) and use that type instead of relying on a global React namespace.
/** @type {React.CSSProperties} Styles for the full-screen background */
const overlayStyle: React.CSSProperties = {
  position: 'fixed',
  top: 0,

web/src/components/organisms/cv-import/UploaderCard.tsx:169

  • The file input onChange forwards the selected file directly to onFileSelect without enforcing the advertised constraints (5MB max, allowed types). Add the same size/type validation here as for drag/drop to prevent unsupported uploads via the file picker.
          <input
            id="cv-input"
            type="file"
            hidden
            accept=".pdf,.doc,.docx"
            onChange={(e) =>
              e.target.files?.[0] && onFileSelect(e.target.files[0])
            }
          />

Comment thread web/src/routes/cv-analysis.tsx
Comment thread web/src/components/organisms/cv-import/UploaderCard.tsx
Comment thread web/src/components/organisms/cv-import/AIProcessingOverlay.tsx Outdated
Comment thread web/src/components/atoms/cv-import/StepIndicator.tsx
Comment thread web/src/components/molecules/cv-import/Stepper.tsx
Comment thread web/src/components/atoms/cv-import/ProgressBar.tsx
Comment thread web/src/components/organisms/cv-import/AnalysisResultCard.tsx
Comment thread web/src/components/organisms/cv-import/AnalysisResultCard.tsx
Comment thread web/src/components/organisms/cv-import/Analysisresultcard.spec.tsx
Comment thread web/src/components/organisms/cv-import/Uploadercard.spec.tsx
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (1)

web/src/components/organisms/cv-import/UploaderCard.tsx:168

  • The file input onChange accepts and forwards any selected file without enforcing the advertised constraints (max size 5MB, PDF/DOC/DOCX). Implement the same validation here as for drag/drop and display an error message when the file is too large or unsupported.
          <input
            id="cv-input"
            type="file"
            hidden
            accept=".pdf,.doc,.docx"
            onChange={(e) =>
              e.target.files?.[0] && onFileSelect(e.target.files[0])
            }

Comment thread web/src/routes/cv-analysis.tsx
Comment thread web/src/routes/cv-analysis.tsx
Comment thread web/src/routes/cv-analysis.tsx
Comment thread web/src/components/organisms/cv-import/UploaderCard.tsx
Comment thread web/src/components/organisms/cv-import/UploaderCard.tsx Outdated
Comment thread web/src/components/organisms/cv-import/Uploadercard.spec.tsx Outdated
Comment on lines +58 to +86
let timeoutId: NodeJS.Timeout;

const interval = setInterval(() => {
setProgress((prev) => {
// Si on est déjà à 100 ou plus, on arrête tout
if (prev >= 100) {
clearInterval(interval);
timeoutId = setTimeout(onFinished, 500);
return 100;
}

// On calcule la prochaine étape sans jamais dépasser 100
const nextProgress = Math.min(prev + 2, 100);

// Mise à jour du message en fonction de la progression réelle corrigée
const msgIndex = Math.floor((nextProgress / 100) * messages.length);
setCurrentMessage(messages[msgIndex] || messages[messages.length - 1]);

return nextProgress;
});
}, 100);

// Nettoyage de l'intervalle ET du timeout au démontage du composant
return () => {
clearInterval(interval);
if (timeoutId) {
clearTimeout(timeoutId);
}
};
Comment thread web/src/components/organisms/cv-import/AIProcessingOverlay.tsx Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants