Skip to content

Conversation

@sahilverma-dev
Copy link
Collaborator

@sahilverma-dev sahilverma-dev commented Aug 31, 2025

Issue:

logic: Implement inline editing for resumes directly from the resume preview

Description:

Implement inline editing functionality within the ResumeView component to allow users to edit resume fields directly from the preview.

Changes Made:

  • Added support for an "editing mode" in the ResumeView component and its sub-components.
  • Enabled inline editing for various types of fields such as text, multi-line text, date, and dropdown/enum fields.
  • Implemented list item management with inline "Edit" and "Delete" options for individual entries.
  • Integrated optimistic updates and backend API calls for seamless editing experience.
  • Enhanced visual feedback and accessibility features for interactive elements.

Closing Note:

This PR enhances user experience by enabling direct inline editing of resume fields from the preview, improving efficiency and reducing context switching for users.

Summary by CodeRabbit

  • New Features
    • Added Privacy Policy and Terms pages with a new legal layout.
    • Introduced dashboard resume search (Algolia), resume cards, and search input.
    • New onboarding flow: welcome reveal, parse-and-upload resume, guided steps, and completion CTA.
    • Revamped App dashboard with base resume surfacing and quick start input.
    • Split resume viewer/editor layout, new tabbed editor design (toggle via env), plus Certifications and Projects editors.
    • Admin resume preview page (token-protected) and resume parsing API.
    • Production-only analytics/error context via PostHog and Sentry user providers.
  • Bug Fixes
    • Corrected responsive class on Changes page heading.
  • Documentation
    • Added CONTRIBUTING; updated LICENSE.
  • Chores
    • Expanded .gitignore; added env flag for editor tabs.
  • Tests
    • Introduced comprehensive testing helpers and extensive UI test suites.

sahilverma-dev and others added 30 commits July 17, 2025 07:43
…view (#155)

* feat: admin protected route to render a resume for screenshotting job
* fix: lint errors
…ll editor fixes (#146)

* feat: integrate SkillsEditor into ResumeEditor component
* feat: add preferred skills recommendation message in SkillsEditor
* lint: fix lint issue
* chore: bun sync reinstall packages in bun.lock
* Create bun.lock
* lint: fix lint issue in Resume editor and tabs
* fix(skill): improve handling of skill categories and enhance API integration for existing skills
* fix(skill): enhance custom skill handling and improve API integration for skill details retrieval
* lint: fix linter issues
* chore: remove debugging colors from ui
* refactor(SkillsEditor): clean up imports by removing unused components
* fix: review code rabbit comments and optimise code quality for skill editor
* refactor(SkillAutocomplete): update skill type to GlobalSkill for improved type safety
* feat: integrate SkillsEditor into ResumeEditor component
* feat: add preferred skills recommendation message in SkillsEditor
* lint: fix lint issue
* chore: bun sync reinstall packages in bun.lock
* Create bun.lock
* feat: integrate SkillsEditor into ResumeEditor component
* feat: add preferred skills recommendation message in SkillsEditor
* lint: fix lint issue
* chore: bun sync reinstall packages in bun.lock
* Create bun.lock
* chore: update Next.js version to 15.2.4 in bun.lock
* fix: update ProficiencySlider logic to prevent out-of-bounds access
* refactor: clean up SkillsEditor by removing unused imports and state variables
* refactor: simplify skill parsing logic in fetchGlobalSkills function
* feat: integrate SkillsEditor into ResumeEditor component
* feat(editor): use expandable tabs from 21st.dev
* lint: fix lint issue in Resume editor and tabs
* fix(skill): improve handling of skill categories and enhance API integration for existing skills
* fix(skill): enhance custom skill handling and improve API integration for skill details retrieval
* lint: fix linter issues
* chore: remove debugging colors from ui
* refactor(SkillsEditor): clean up imports by removing unused components
* fix: review code rabbit comments and optimise code quality for skill editor
* refactor(SkillAutocomplete): update skill type to GlobalSkill for improved type safety
* fix: resolve merge conflicts
* fix: remove unnecessary resume prop from ResumeEditor
* fix: Refactor ResumeEditor to use conditional rendering
* feat(skill-editor): build autocomplete for the skill categories
* lint: fix lint issue
* feat(skill-editor): add smooth animation for the proficiency slider
* fix(ProficiencySlider): enhance cleanup logic to close audio context on unmount
…g and the dashboard (#154)

* feat: go-to-dashboard button on onboarding last step
* fix: view-transition not working when navigating to dashboard from onboarding
* feat: welcome animation on dashboard with mask reveal
* fix: add group class on button to enable animation on arrow
* chore: implement CodeRabbit suggestions
* feat: auto-redirect to onboarding and leave-off continuation
* fix: remove deprecated afterSignOutUrl signature
* fix: users not being redirected to app after sign up
* chore: implement CodeRabbit suggestions
* fix: build failing due to enum type expectation from OnboardingSteps
* fix: onboarding hooks type issues
* fix: onboarding forms doesn't reset properly, current indicator for onboarding forms and location aware country pre-selection
* feat: education & experience list item expand on hover on onboarding
* fix: list of education and experience isn't scrollable
* fix: sanitize HTML content in education & experience list
* fix: remove smooth scrolling from education & experience list
* fix: update education component container height for responsive sizing
* feat: add certifications tab and editor to ResumeEditor component
* refactor: integrate DatePicker for issue date input, improve date formatting for API compatibility, and enhance validation in CertificationMutation schema.
* refactor: update CertificationEditor to handle optional issuing organization and issue date, improve API compatibility in actions, and enhance validation in CertificationMutation schema.
* style: minor styling improvements

---------

Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
…esign (#162)

* feat(editor): Add feature flag for new resume editor tabs design
* fix: animations of individual resume editors
* fix: restore design flare on traditional tabs

---------

Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
* feat(ProjectEditor): Integrate ProjectEditor into ResumeEditor component
* refactor(ProjectEditor): streamline project mutation handling and enhance error messaging
* refactor(ProjectEditor): enhance skills section by grouping skills by category and improving display
* fix(ResumeEditor): correct indentation for Projects tab entry
* refactor(ProjectEditor): update skill category handling to allow null values and improve URL formatting logic
* refactor(ProjectEditor): enhance skill management by integrating resume skills and improving skill input handling
* fix(ProjectEditor): correct indentation for skill addition logic in ProjectEditor component
* style(ProjectEditor): design improvements and animations

---------

Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
* feat(resume): Add Skills section support to default resume theme
* lint(resume): fix lint issue
… Clerk's SDK (#166)

* feat: identify users in Sentry from Next.js service through Clerk's SDK
* fix: improve type safety in user ID handling in sentry configs
* chore: remove duplicate redundant logic
… Clerks's SDK (#169)

* feat: identify users in Posthog from NextJS service through Clerks's SDK
* fix: implement CodeRabbit suggestion
* feat: loading indicator skeleton for resume views and resume editors
* feat: improve resume page animation with smooth transition
* fix: lint errors
* feat: improve resume editor skeleton by including tabs & intelligent editor header skeleton usage
* fix: deterministic randomization to avoid hydration error
* fix: implement CodeRabbit suggestion
* feat(resume): Add Projects section support to default resume theme
* refactor(resume): Remove accomplishments handling from ProjectController and ProjectsSection
* fix(ProjectsSection): Update project links separator to use aria-hidden span for improved accessibility
* feat(ProjectsSection): Add project separator styling for improved layout and accessibility
* feat(resume): Add Certification section support to default resume theme
* refactor(CertificationController): Extract month names to a constant for improved readability in date formatting
* feat: add comprehensive test utilities and helpers for vitest unit testing
* test: fix date timezone handling and window mocking in lib/utils tests
* test: cover ShadCN button component with unit test
* test: set up test execution scripts and watch mode
* fix: type errors in test configurations
* test: create additional component tests for complex components
* fix: type errors and import path
* feat: add tests for API utilities and business logic
* fix: change relative path imports to import aliases
* test: unit tests for resume system components
* test: unit tests for education editor components
* fix: type errors in ResumeViewer.test.tsx
* test: unit tests for ExperienceEditor component
* test: unit tests for PersonalDetailsEditor component
* test: unit tests for SkillEditor component
* test: unit tests for ThemeFactory component
* test: unit tests for DefaultTheme component
* test: unit tests for PersonalInfoSection component
* test: unit tests for education & experience resume sections
* fix: lint errors
* fix: type issues in test files
* test: unit tests for onboarding components
* test: unit tests for BaseResume component
* fix: file location for test file of BaseResume component
* test: add tests for skill server actions
* test: add tests for experience server actions
* fix: streamline server actions for resume
* test: unit tests for resume server actions
* fix: lint errors in test of resume server actions
* test: add unit tests for onboarding server actions
* test: unit tests for query & mutation hooks of skill & experience
* fix: lint errors in unit test file
* test: unit tests for education query & mutation hooks
* test: unit tests for resume query & mutation hooks
* test: unit tests for user-info query & mutation hooks
* fix: lint errors in unit test files
* fix: import paths to alias based from relative
* test: unit tests for ErrorView component
* test: unit tests for TextAnimations component
* test: unit tests for WebsiteNavBar component
* fix: lint errors in TextAnimations unit test file
* test: unit tests for AppSidebar component
* test: unit tests for AppLayoutContainer component
* test: unit tests for RichTextEditor component
* test: unit tests for Toolbar component
* chore: fix merge conflicts
…pected and real data of resume object (#175)

* fix: resume parsing fails due to mismatch parser configuration
* fix: middleware lint issues
* feat: Add auto-focus hooks to resume editor components
* feat(resume): Integrate ResumeHighlightContext for enhanced item highlighting across editors and sections
* refactor(resume): Remove console logs from ResumeHighlightContext and editors for cleaner code
* lint: fix linter issues
* feat(resume): Enhance ResumeHighlightContext with timeout management for highlighting and scrolling
* feat(resume): Update generateSelector to handle missing item IDs and add certification case
* feat(resume): Enhance useAutoFocus and useAutoFocusField hooks to support scoped element focusing and increase default delay
* feat(resume): Implement cleanup for timeouts in ResumeHighlightContext to prevent memory leaks on component unmount
* feat(resume): Add inline scrolling behavior to ResumeHighlightContext for improved element visibility
* fix(resume): Clean up formatting in useAutoFocus and useAutoFocusField hooks for improved readability
* fix(resume): Add scroll threshold check in ResumeHighlightContext to prevent unnecessary scrolling for already visible elements
* fix(resume): Adjust scroll threshold to 100 pixels and implement breathing room for improved element visibility in ResumeHighlightContext
* fix(resume): Refactor scrolling logic in ResumeHighlightContext to improve element visibility and ensure optimal scroll position within scrollable containers
* feat(resume): Introduce clearHighlight function in ResumeHighlightContext and update editors to utilize it for improved highlight management
* feat(resume): Add TitleDimWrapper component to manage title dimming effect on highlight and refactor title components for cleaner implementation
* feat(resume): Integrate useAutoFocusField hook in CertificationEditor and ProjectEditor to auto-focus the first field when the form is opened
* feat: transition for highlighting in resume preview
* feat: include certification section in the overall improvement

---------

Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
…re validation mismatch (#177)

* fix: resume structure mismatch & preview route error
* fix: type errors in unit test
* fix: update description of the status field in job
… structured content (#179)

* feat: initial implementation of uploaded resume parsing and processing
* fix: improve model response time
* fix: sanitize old resume tailoring flow & implement CodeRabbit suggestion
* chore: improve generic schema to return description more deterministically for resume
* chore: implement CodeRabbit suggestion
* chore: improve null handling of job data
…data automatically during onboarding (#185)

* fix: project type mismatch with backend's signature
* feat: build and polish UI for uploading existing resume during onboarding
* feat: logic for uploading and parsing resume files during onboarding
* feat: api mutation for replacing a resume details by id
* feat: wire api mutation for parsing resume and updating base resume
* feat: optimize resume parsing, default_theme styling fix
* chore: replace console statements with toast notifications.
* chore: fix lint errors
* fix: list not scrollable for education, experience, certification and skills
* feat: animation and overall UX improvement on resume parsing feature
* fix: key error
* chore: implement CodeRabbit suggestions
* Fix education query options import and usage
* fix: implement CodeRabbit suggestion
* fix: streamline prompt by removing redundant skill_id generation
…n the dashboard (#187)

* feat: data fetching integration for getting all resumes
* chore: remove redundant console.logs
* feat: display resume cards in dashboard
* chore: implement CodeRabbit suggestions
…az (#191)

* feat: create privacy policy and terms of use pages
* chore: remove decorative image from accessibility tree
* fix: spacing issue and CodeRabbit suggestion
* fix: implement shared layout for legal pages & optimize decorative image size
* fix: lint errors
…he resume, as the system supports date up to current date-time (#189)
…#192)

* feat: implement search functionality in the client-side app using Algolia
* feat: add @mantine/hooks dependency and update dashboard resume grid for improved filtering and search functionality
* refactor: replace DashboardResumeGrid with ResumeCard in AppHome and update search container to use ResumeSearch component
* feat: enhance DashboardSearchInput with focus state and update ResumeCard to highlight search query in job details
* refactor: update component exports to use consistent function declarations and improve code readability
* fix: fix linter issues
* fix: replace deprecated instantSearch package with newer version
* refactor: clean up env.ts formatting, update DashboardSearchContainer and DashboardSearchInput styles, and correct import paths for ResumeSearch component
* fix: uncomment redirect logic for users who have completed onboarding to ensure proper navigation to the main app
* fix: add aria-label for accessibility in DashboardSearchInput and prevent rendering of ResumeSearch component when userId is not provided
* fix: scrollbar on thumbnails, relative path import & non-optional algolia env variables
* feat: dashboard new layout design improvement
* style: padding unification in search input and resume-grid
* fix: temporary disable sentry component annotation
* feat: enhance Algolia search results handling with caching and smart scrolling
* feat: conditionally render DashboardSearchContainer based on user resumes and highlight job location in ResumeCard
* refactor: improve type safety in ResumeSearch component and update grid selector in DashboardSearchContainer
* refactor: optimize caching and scrolling behavior in ResumeSearch component for improved user experience
* refactor: update Algolia search results handling to use 'items' instead of deprecated 'hits' for improved compatibility
* refactor: enhance error handling in Algolia search results by enabling catchError option in useInstantSearch

---------

Co-authored-by: Sourabh Rathour <rathoursourabh5@gmail.com>
Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
sourabhrathourr and others added 12 commits August 19, 2025 12:18
* feat: Enhance NewResumeInput component with URL validation and resume tailoring functionality
* fix: improve resume processing UI
* lint: fix linter issues
* feat: Replace AiLoading with ResumeAiLoading component in processing UI
* refactor: Remove unused loading messages and optimize loading component styles in resume processing UI
* lint: fix linter issues
* feat: Update resume editors to utilize resumeId from URL parameters for certification, education, experience, and project
* feat: Update resume editors and queries to include resumeId for improved data handling
* chore: fix lint issues
* refactor: Simplify processing UI logic and enhance loading state handling in ResumeAiLoading component
* feat: Integrate resumeId into skill and project mutations and queries for consistent data handling across editors
* refactor: Remove console logging from experience mutation functions for cleaner code
* Update React Compiler to latest RC version
* chore: fix lint issues
* Pass resumeId explicitly to query hooks
* refactor: Update query options to use default resumeId for improved flexibility in data fetching
* fix: lint errors
* attempt: remove project normalization from getProjectsFromDB action (double-check)
* feat: replace AILoading with updated animation video
* refactor: update query options and mutation parameters for education and experience components
* fix: pass resumeId to useCurrentResumeSkills for accurate data fetching
* fix: pass resumeId to useSkillCategories for accurate data fetching
* fix: update skill data access in SkillsEditor for correct mutation handling
* fix: normalize thumbnail url to account for lack of protocol in URL

---------

Co-authored-by: Subhajit Kundu <subha60kundu@gmail.com>
…andles in ReorderableSections and enhance SaveIndicator with tooltip functionality in EducationSection
… with improved error handling and type safety
…ave functionality and improved user interaction
…with debounced save functionality and improved user interaction
@vercel
Copy link

vercel bot commented Aug 31, 2025

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

Project Deployment Preview Comments Updated (UTC)
letraz Ready Ready Preview Comment Aug 31, 2025 6:30am

@coderabbitai
Copy link

coderabbitai bot commented Aug 31, 2025

Caution

Review failed

Failed to post review comments.

Walkthrough

Adds extensive testing infrastructure and suites, new onboarding flows (resume parsing/upload, flow control, welcome), dashboard search components, resume editor/view revamp with controllers and new editors (Skills, Certifications, Projects) with per-resume data, new providers (Sentry/PostHog identity), admin resume preview, legal pages, UI animations/styles, env flag, and removes legacy JD parsing/summarization.

Changes

Cohort / File(s) Summary
Environment & Repo Meta
/.env.example, /.gitignore, /CONTRIBUTING.md, /LICENSE
Adds NEXT_PUBLIC_RESUME_EDITOR_TABS_NEW_DESIGN_ENABLED=true; ignores IDE folders; adds contribution policy; updates copyright.
Global Styles
/app/globals.css
Adds loading shimmers, ring glows, radial border, and animated border keyframes/utilities.
Providers & Layout
/app/layout.tsx, /components/providers/PosthogProvider.tsx, /components/providers/SentryUserProvider.tsx
Wraps app with SentryUserProvider; production-gated PostHog with Clerk-based identify/group; tweaks ClerkProvider; adjusts layout typing/attributes.
Legal Pages
/app/(website)/(legal)/layout.tsx, /app/(website)/(legal)/privacy/page.tsx, /app/(website)/(legal)/terms/page.tsx
Adds Legal layout and static Privacy/Terms pages with metadata.
Website & Navigation
/app/(website)/page.tsx, /app/(website)/changes/page.heading.tsx, /components/WebsiteNavBar.tsx
Adds landing overlay links to Terms/Privacy; fixes Tailwind typo; minor formatting in navbar.
Auth
/app/(auth)/signup/[[...sign-up]]/page.tsx
Sets SignUp fallbackRedirectUrl to “/app”.
Admin Resume Preview
/app/admin/resumes/[resumeId]/page.tsx
Adds server page to fetch and render resume by ID with token validation and metadata.
Public API
/app/api/resume/parse/route.ts
New POST /api/resume/parse for form-data file validation and parsing; exports runtime='nodejs'.
App Home & Dashboard
/app/app/page.tsx, /components/dashboard/*
Makes AppHome async; adds DashboardSearchInput, DashboardSearchContainer, Algolia-backed ResumeSearch, and ResumeCard.
Onboarding Flow – Pages & Types
/app/app/onboarding/page.tsx, /app/app/onboarding/types.ts
Parallel prefetch with Promise.all; replaces enum with const type+values and ONBOARDING_STEPS export.
Onboarding – Components
/components/onboarding/*
Adds ParseResume, OnboardingFlowControl, OnboardingWelcome, BaseResumeProvider, OnboardingCompletionButton; updates About/Welcome to call updateOnboardingStep; refactors PersonalDetails to use flow control; enhances Education/Experience UIs and mutations; improves form defaults and country autodetect; controlled inputs.
Processing Flow
/app/app/craft/resumes/[resumeId]/page.tsx, /app/app/craft/resumes/[resumeId]/processing.client.tsx
Adds processing server/client components to view processing state and render viewer+editor.
New Resume Input
/components/NewResumeInput.tsx
Switches from JD parsing to tailor-resume mutation, adds Cmd/Ctrl+Enter submit, updated validation/UI/overlay.
Removed Legacy AI Flows
/app/app/craft/parseJD.ts (deleted), /app/app/craft/summarize/route.ts (deleted), /components/JobSummary.tsx (deleted)
Removes AI JD parser, job summarization route, and related UI components.
Resume View & Editor
/components/resume/ResumeView.tsx, /components/resume/ResumeViewer.tsx, /components/resume/ResumeEditor.tsx, /components/resume/ReorderableSections.tsx, /components/resume/contexts/ResumeHighlightContext.tsx
Converts to animated two-pane view with skeleton/error states; ResumeViewer gains showAnimation prop; ResumeEditor adds feature-flagged tab design with new tabs and isTabSwitch prop plumbing; ReorderableSections requires resumeId and conditional drag handles; adds ResumeHighlightContext.
Resume Controllers
/components/resume/controllers/*
Adds/updates controllers for Education, Experience, Certification, Project, Skills with new public types/fields and render-prop hooks.
Resume Editors
/components/resume/editors/*
Adds CertificationEditor and ProjectEditor; refactors Education/Experience/Skills/PersonalDetails to per-resume query keys, highlight/scroll, animations, skeletons, and isTabSwitch prop.
Animations
/components/animations/*
Adds DEFAULT_FADE/SLIDE constants, StaggeredText, and ParticlesBurst animation component.
Notifications
/components/notifications/NotificationFeed.tsx
Adjusts import to absolute alias.
Sidebar
/components/AppSidebar.tsx
Formatting only.
Testing Infrastructure
/__tests__/helpers/*, __tests__/*.test.*, components/**/__tests__/*.test.*
Adds fetch mock manager, mock factories, utility helpers, render wrappers, and comprehensive test suites for helpers, utils, React setup, onboarding, dashboard, sidebar, website navbar, resume components, and editors.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as NewResumeInput
  participant API as Tailor Resume API
  participant Router as Next Router
  User->>UI: Enter job URL/description + submit
  UI->>API: mutate({ target })
  API-->>UI: { id }
  UI->>Router: push /app/craft/resumes/{id}
Loading
sequenceDiagram
  autonumber
  actor User
  participant Page as ParseResume (Onboarding)
  participant API as /api/resume/parse
  participant SVC as ReplaceResume(base)
  participant Router as Next Router
  User->>Page: Drop/upload file
  Page->>API: POST form-data (file, format)
  API-->>Page: { parsed resume payload }
  Page->>SVC: mutate({ resumeId:'base', data })
  SVC-->>Page: success
  Page->>Router: replace /app/onboarding?step=resume
Loading
sequenceDiagram
  autonumber
  participant Clerk as Clerk (auth)
  participant Sentry as SentryUserProvider
  participant PH as PosthogProvider
  Clerk-->>Sentry: userId, user (loaded)
  Sentry->>Sentry: setUser/clearUser + tags
  Clerk-->>PH: userId, user (loaded)
  PH->>PH: posthog.identify / group / reset (prod only)
Loading
sequenceDiagram
  autonumber
  participant AdminPage as /admin/resumes/[id]
  participant Env as ENV (API_URL, ADMIN_KEY)
  participant Backend as Admin API
  AdminPage->>AdminPage: validate token=SELF_SECRET_KEY
  AdminPage->>Backend: GET /admin/resumes/{id} (no-store)
  Backend-->>AdminPage: Resume | 404
  AdminPage-->>AdminPage: notFound() on 404/error
  AdminPage->>UI: Render ResumeViewer (no anim) + Provider
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit taps keys with a cheerful thrum,
New tabs pop open—beat of a drum.
Resumes reshuffle, particles burst,
Onboarding whispers, “Upload it first.”
Tests burrow deep, providers align—
Now the garden of code feels mighty fine. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sahil/let-103-logic-implement-inline-editing-for-resumes-directly-from-the

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 81

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
app/(website)/changes/page.heading.tsx (1)

21-24: Add rel="noopener noreferrer" to external link opened with target="_blank".

Prevents reverse tabnabbing and isolates the opener window.

Apply this diff:

-				Join our <a href={discordHandle}
-					target="_blank"
+				Join our <a href={discordHandle}
+					target="_blank" rel="noopener noreferrer"
 					className="font-semibold text-flame-500 focus-visible:underline hover:underline"
 				>Discord</a> to stay connected to more frequent updates and help us build the community
.env.example (1)

25-26: Document and default new design feature flag in .env.example
Parsing via strict === 'true' in ResumeEditor.tsx is already correct; no helper needed.

Add a docs section and default the flag to false:

+## UI flags
+# Toggle the new Resume Editor tabs design (client-side). Accepts "true" | "false".
-NEXT_PUBLIC_RESUME_EDITOR_TABS_NEW_DESIGN_ENABLED=true
+NEXT_PUBLIC_RESUME_EDITOR_TABS_NEW_DESIGN_ENABLED=false
components/notifications/NotificationFeed.tsx (1)

60-61: Enforce safe URL protocols in sanitizeHtml
lib/utils.ts: sanitizeHtml currently uses DOMPurify with ALLOWED_TAGS and ALLOWED_ATTR but doesn’t restrict URI schemes, so href="javascript:…" still passes. Add a protocol whitelist (e.g. ALLOWED_URI_REGEXP: /^(?:https?:|mailto:|tel:)/i) or a hook to strip unsafe protocols, and add tests to cover javascript: links.

components/resume/controllers/ExperienceController.tsx (1)

96-99: Populate dates.current.

Keeps data shape consistent with the interface.

-    const dates = {
-      hasDates: Boolean(dateRange),
-      formatted: dateRange
-    }
+    const dates = {
+      hasDates: Boolean(dateRange),
+      formatted: dateRange,
+      current: Boolean(experience.current)
+    }
components/resume/editors/shared/CountrySelect.tsx (1)

60-71: Guard Next/Image src; avoid rendering with empty/unknown flag.

countries.find(...) may return undefined; passing '' to Image src will throw. Also avoid repeated finds.

Apply this diff:

-								<SelectValue placeholder={placeholder}>
-									{field.value && (
-										<span className="flex items-center">
-											<Image
-												src={countries.find(c => c.code === field.value)?.flag || ''}
-												width={64}
-												height={64}
-												alt={`The flag of ${countries.find(c => c.code === field.value)?.name}`}
-												className="mr-2 w-6"
-											/>
-											{countries.find(c => c.code === field.value)?.name || field.value}
-										</span>
-									)}
-								</SelectValue>
+								<SelectValue placeholder={placeholder}>
+									{field.value && (() => {
+										const selected = countries.find(c => c.code === field.value)
+										return (
+											<span className="flex items-center">
+												{selected ? (
+													<>
+														<Image
+															src={selected.flag}
+															width={64}
+															height={64}
+															alt={`The flag of ${selected.name}`}
+															className="mr-2 w-6"
+														/>
+														{selected.name}
+													</>
+												) : (
+													field.value
+												)}
+											</span>
+										)
+									})()}
+								</SelectValue>
components/resume/editors/ExperienceEditor.tsx (1)

154-158: Remove incorrect label-to-code conversion for employment_type
In components/resume/editors/ExperienceEditor.tsx the edit handler assumes experience.employment_type is a label and looks up its code (type.label === experience.employment_type), but the model already stores the code (e.g. 'flt'), so it always falls back to 'flt'. Remove that lookup and reset the form with the code directly:

- // Find the employment type code that matches the label in the data
- const employmentTypeCode = employmentTypes.find(
-   type => type.label === experience.employment_type
- )?.value || 'flt'
  form.reset({
    ...experience,
-   employment_type: employmentTypeCode,
+   employment_type: experience.employment_type,
    country: experience.country.code,
    started_from_month: experience.started_from_month?.toString() || null,
    /* … */
  })
components/resume/editors/EducationEditor.tsx (1)

188-195: Fix: possible crash when country is undefined in edit mode

Accessing education.country.code will throw if country is null/undefined. Use optional chaining with a safe fallback.

-      country: education.country.code,
+      country: education.country?.code ?? '',
components/resume/editors/SkillsEditor.tsx (1)

239-257: Potential crash when skill.alias is undefined

skill.alias.some(...) assumes alias exists. Guard it to avoid runtime errors with incomplete data.

- .filter(skill => (skill.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
-          skill.category?.toLowerCase().includes(searchQuery.toLowerCase()) ||
-          skill.alias.some(alias => alias.name.toLowerCase().includes(searchQuery.toLowerCase()))) &&
+ .filter(skill => (skill.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+          skill.category?.toLowerCase().includes(searchQuery.toLowerCase()) ||
+          (Array.isArray(skill.alias) && skill.alias.some(a => a.name.toLowerCase().includes(searchQuery.toLowerCase())))) &&
           !resumeSkills.some(rs => rs.skill.id === skill.id))

Comment on lines +55 to +59
if (pattern instanceof RegExp) {
matches = pattern.test(url)
} else {
matches = url.includes(pattern)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reset RegExp lastIndex to avoid flaky matches with /g or /y

.test() on global/sticky regex mutates lastIndex and may intermittently fail on repeated calls.

Apply:

-      if (pattern instanceof RegExp) {
-        matches = pattern.test(url)
+      if (pattern instanceof RegExp) {
+        pattern.lastIndex = 0
+        matches = pattern.test(url)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (pattern instanceof RegExp) {
matches = pattern.test(url)
} else {
matches = url.includes(pattern)
}
if (pattern instanceof RegExp) {
pattern.lastIndex = 0
matches = pattern.test(url)
} else {
matches = url.includes(pattern)
}
🤖 Prompt for AI Agents
In __tests__/helpers/api-mocks.ts around lines 55 to 59, the use of
pattern.test(url) on a RegExp can be flaky because .test() mutates lastIndex for
global (g) or sticky (y) regexes; before calling test(), reset pattern.lastIndex
= 0 (or clone the RegExp without those flags) so repeated calls behave
deterministically, then proceed to call pattern.test(url).

Comment on lines +75 to +116
const setupFetchMock = (): void => {
global.fetch = vi.fn().mockImplementation(async (url: string, init?: RequestInit) => {
const mockConfig = fetchMockManager.getMockResponse(url, init)

if (!mockConfig) {
throw new Error(`No mock configured for URL: ${url}`)
}

// Simulate network delay if specified
if (mockConfig.delay) {
await new Promise(resolve => setTimeout(resolve, mockConfig.delay))
}

const {
data = null,
status = 200,
statusText = 'OK',
headers = {}
} = mockConfig

const response = {
ok: status >= 200 && status < 300,
status,
statusText,
headers: new Headers(headers),
url,
redirected: false,
type: 'basic' as ResponseType,
body: null,
bodyUsed: false,
clone: vi.fn(),
json: vi.fn().mockResolvedValue(data),
text: vi.fn().mockResolvedValue(JSON.stringify(data)),
arrayBuffer: vi.fn().mockResolvedValue(new ArrayBuffer(0)),
blob: vi.fn().mockResolvedValue(new Blob()),
formData: vi.fn().mockResolvedValue(new FormData()),
bytes: vi.fn().mockResolvedValue(new Uint8Array())
}

return response as Response
})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle Request and URL inputs in fetch mock to avoid runtime errors

Current mock assumes the first arg is a string. Real fetch callers often pass Request or URL, which will break matching and verification.

Apply:

-const setupFetchMock = (): void => {
-  global.fetch = vi.fn().mockImplementation(async (url: string, init?: RequestInit) => {
-    const mockConfig = fetchMockManager.getMockResponse(url, init)
+const setupFetchMock = (): void => {
+  global.fetch = vi.fn().mockImplementation(async (input: RequestInfo | URL, init?: RequestInit) => {
+    const url =
+      typeof input === 'string'
+        ? input
+        : input instanceof URL
+          ? input.toString()
+          : (input as Request).url
+
+    const mockConfig = fetchMockManager.getMockResponse(url, init)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const setupFetchMock = (): void => {
global.fetch = vi.fn().mockImplementation(async (url: string, init?: RequestInit) => {
const mockConfig = fetchMockManager.getMockResponse(url, init)
if (!mockConfig) {
throw new Error(`No mock configured for URL: ${url}`)
}
// Simulate network delay if specified
if (mockConfig.delay) {
await new Promise(resolve => setTimeout(resolve, mockConfig.delay))
}
const {
data = null,
status = 200,
statusText = 'OK',
headers = {}
} = mockConfig
const response = {
ok: status >= 200 && status < 300,
status,
statusText,
headers: new Headers(headers),
url,
redirected: false,
type: 'basic' as ResponseType,
body: null,
bodyUsed: false,
clone: vi.fn(),
json: vi.fn().mockResolvedValue(data),
text: vi.fn().mockResolvedValue(JSON.stringify(data)),
arrayBuffer: vi.fn().mockResolvedValue(new ArrayBuffer(0)),
blob: vi.fn().mockResolvedValue(new Blob()),
formData: vi.fn().mockResolvedValue(new FormData()),
bytes: vi.fn().mockResolvedValue(new Uint8Array())
}
return response as Response
})
}
const setupFetchMock = (): void => {
global.fetch = vi.fn().mockImplementation(async (input: RequestInfo | URL, init?: RequestInit) => {
const url =
typeof input === 'string'
? input
: input instanceof URL
? input.toString()
: (input as Request).url
const mockConfig = fetchMockManager.getMockResponse(url, init)
if (!mockConfig) {
throw new Error(`No mock configured for URL: ${url}`)
}
// Simulate network delay if specified
if (mockConfig.delay) {
await new Promise(resolve => setTimeout(resolve, mockConfig.delay))
}
const {
data = null,
status = 200,
statusText = 'OK',
headers = {}
} = mockConfig
const response = {
ok: status >= 200 && status < 300,
status,
statusText,
headers: new Headers(headers),
url,
redirected: false,
type: 'basic' as ResponseType,
body: null,
bodyUsed: false,
clone: vi.fn(),
json: vi.fn().mockResolvedValue(data),
text: vi.fn().mockResolvedValue(JSON.stringify(data)),
arrayBuffer: vi.fn().mockResolvedValue(new ArrayBuffer(0)),
blob: vi.fn().mockResolvedValue(new Blob()),
formData: vi.fn().mockResolvedValue(new FormData()),
bytes: vi.fn().mockResolvedValue(new Uint8Array())
}
return response as Response
})
}
🤖 Prompt for AI Agents
In __tests__/helpers/api-mocks.ts around lines 75 to 116, the fetch mock assumes
the first argument is a string which breaks when callers pass a Request or URL;
update the mock implementation to normalize the inputs by detecting if the first
arg is a Request, URL, or string, extracting the URL string (use request.url or
url.toString()), and when a Request is passed also extract its init-like values
(method, headers, body) to pass into fetchMockManager.getMockResponse; then use
the normalized url string for error messages and matching so getMockResponse
receives a consistent URL string and the thrown error includes the normalized
URL.

Comment on lines +231 to +238
if (url) {
const calls = fetchMock.mock.calls.filter(call => {
const callUrl = call[0] as string
if (url instanceof RegExp) {
return url.test(callUrl)
}
return callUrl.includes(url)
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify helper must support Request/URL inputs

verifyFetchCalled casts to string and misses Request/URL cases, causing false negatives.

Apply:

-        const callUrl = call[0] as string
+        const arg = call[0]
+        const callUrl =
+          typeof arg === 'string'
+            ? arg
+            : arg instanceof URL
+              ? arg.toString()
+              : (arg as Request).url
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (url) {
const calls = fetchMock.mock.calls.filter(call => {
const callUrl = call[0] as string
if (url instanceof RegExp) {
return url.test(callUrl)
}
return callUrl.includes(url)
})
if (url) {
const calls = fetchMock.mock.calls.filter(call => {
const arg = call[0]
const callUrl =
typeof arg === 'string'
? arg
: arg instanceof URL
? arg.toString()
: (arg as Request).url
if (url instanceof RegExp) {
return url.test(callUrl)
}
return callUrl.includes(url)
})
🤖 Prompt for AI Agents
In __tests__/helpers/api-mocks.ts around lines 231 to 238, verifyFetchCalled
wrongly assumes fetchMock call[0] is a string and therefore misses cases where
the request argument is a Request or URL; update the filter to detect if call[0]
is a Request (use (call[0] as Request).url), a URL (use (call[0] as URL).href or
toString()), or already a string, and normalize to a string before testing
against the provided url (handling url being a RegExp, URL, Request, or string)
so Request/URL inputs are correctly matched.

Comment on lines +133 to +147
// Job-related mock data
export const createMockJob = (overrides?: Partial<Job>): Job => ({
title: 'Software Engineer',
company_name: 'Test Company',
description: 'Test job description',
requirements: ['React', 'TypeScript'],
location: 'Remote',
job_url: 'https://example.com/job',
currency: 'USD',
salary_min: 80000,
salary_max: 120000,
responsibilities: ['Build web applications'],
benefits: ['Health insurance', 'Remote work'],
...overrides
})
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure createMockJob matches the latest Job type.

If Job adds/renames fields, this factory will silently drift.


🏁 Script executed:

#!/bin/bash
# Show JobSchema shape and usages
rg -nP 'JobSchema|type\s+Job\s*=' --type=ts -C3

Length of output: 2961


Sync createMockJob with the current Job schema. Update the mock factory so its default properties exactly match z.infer<typeof JobSchema>—add any newly required fields and remove or rename any that no longer exist.

🤖 Prompt for AI Agents
In __tests__/helpers/mock-factories.ts around lines 133 to 147, the
createMockJob factory no longer matches the current Job schema inferred from
JobSchema; update the factory so its default properties exactly mirror
z.infer<typeof JobSchema> by (1) comparing the JobSchema fields and types and
adding any newly required fields (with reasonable defaults), (2) removing or
renaming properties that no longer exist (e.g., company_name → companyName,
salary_min → salaryMin, etc.) to match schema keys, (3) ensuring optional fields
are present or omitted according to the schema and type-correct (arrays vs
strings vs numbers), and (4) keeping the final ...overrides spread so tests can
override defaults; adjust imports if necessary to reference JobSchema/Job type
used in the tests.

Comment on lines +1 to +2
import {describe, expect, it} from 'vitest'
import {render, screen} from '@testing-library/react'
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure jest-dom matchers are registered globally

These tests rely on jest-dom matchers (toBeInTheDocument, toBeVisible, toHaveTextContent). Please verify global setup; otherwise they’ll fail with “expect(...).toBeInTheDocument is not a function.”

Run to verify configuration:

If missing, add:

// vitest.setup.ts
import '@testing-library/jest-dom/vitest'
// vitest.config.ts
import {defineConfig} from 'vitest/config'
export default defineConfig({
  test: {
    environment: 'jsdom',
    setupFiles: ['./vitest.setup.ts'],
  },
})

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for jest-dom setup and jsdom environment..."
rg -n "jest-dom/(vitest|extend-expect)" -S || echo "NOT FOUND: jest-dom extension import"
fd -a "vitest.setup.*" || echo "No vitest.setup.* file found"
cfgs=$(fd -a "vitest.config.*" || true)
if [ -n "$cfgs" ]; then
  rg -n "setupFiles\s*:\s*\[.*vitest\.setup" -S $cfgs || echo "setupFiles not pointing to vitest.setup.*"
  rg -n "environment\s*:\s*['\"]jsdom['\"]" -S $cfgs || echo "jsdom environment not set in vitest config"
else
  echo "No vitest config file found"
fi

Length of output: 698


Add and configure Vitest setup for jest-dom matchers

Tests rely on jest-dom matchers but no setup file is registered and setupFiles isn’t configured in vitest.config.ts. Add a vitest.setup.ts file containing

import '@testing-library/jest-dom/vitest'

and update vitest.config.ts under test to include:

environment: 'jsdom',
setupFiles: ['./vitest.setup.ts'],

so that jest-dom matchers are loaded globally.

🤖 Prompt for AI Agents
In __tests__/react-setup.test.tsx around lines 1 to 2, tests use jest-dom
matchers but there is no global setup file registered; create a new
vitest.setup.ts at project root that imports '@testing-library/jest-dom/vitest',
and update vitest.config.ts test options to set environment to 'jsdom' and add
setupFiles pointing to ['./vitest.setup.ts'] so the jest-dom matchers are loaded
for all tests.

Comment on lines +80 to +85
// Process links
const links = {
hasLinks: Boolean(project.github_url || project.live_url),
github: project.github_url || undefined,
live: project.live_url || undefined
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sanitize/validate external URLs to prevent javascript:/data: XSS.

github_url/live_url can be user-controlled; passing them directly into anchors risks XSS. Whitelist protocols and normalize before exposing.

Apply this diff:

-    const links = {
-      hasLinks: Boolean(project.github_url || project.live_url),
-      github: project.github_url || undefined,
-      live: project.live_url || undefined
-    }
+    const safeGithub = ensureSafeUrl(project.github_url)
+    const safeLive = ensureSafeUrl(project.live_url)
+    const links = {
+      hasLinks: Boolean(safeGithub || safeLive),
+      github: safeGithub,
+      live: safeLive
+    }

Add this helper in the module (top-level), or centralize in a shared util:

function ensureSafeUrl(url?: string | null): string | undefined {
  if (!url) return undefined
  const trimmed = url.trim()
  // allow only https/http/mailto; drop everything else (e.g., javascript:, data:)
  return /^(https?:\/\/|mailto:)/i.test(trimmed) ? trimmed : undefined
}
🤖 Prompt for AI Agents
In components/resume/controllers/ProjectController.tsx around lines 80 to 85,
the github_url/live_url are used directly which can allow javascript:/data: XSS;
add a top-level helper (or import a shared util) like ensureSafeUrl(url) that
trims the string and only returns it if it matches a whitelist of protocols
(http:, https:, mailto:) otherwise returns undefined, then replace direct uses
of project.github_url and project.live_url with
ensureSafeUrl(project.github_url) and ensureSafeUrl(project.live_url) when
building the links object so only normalized, safe URLs are exposed to anchors.

@@ -0,0 +1,554 @@
import React from 'react'
import {fireEvent, render, screen, waitFor} from '@testing-library/react'
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use the project’s render helper to include providers.

SkillsEditor likely depends on shared providers (e.g., QueryClient). Use the custom render to avoid hidden coupling issues.

-import {fireEvent, render, screen, waitFor} from '@testing-library/react'
+import {fireEvent, render, screen, waitFor} from '@/__tests__/helpers/test-utils'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {fireEvent, render, screen, waitFor} from '@testing-library/react'
import {fireEvent, render, screen, waitFor} from '@/__tests__/helpers/test-utils'
🤖 Prompt for AI Agents
In components/resume/editors/__tests__/SkillsEditor.test.tsx around line 2, the
test imports render directly from @testing-library/react but SkillsEditor relies
on shared providers (e.g., QueryClient); update the test to use the project's
custom render helper that wraps components with the required providers (replace
the import of render from @testing-library/react with the project's render
helper import, remove the direct render import, and call that custom render in
tests), and ensure any waitFor/fireEvent/screen imports remain from
@testing-library/react so the component is rendered with the proper provider
context.

Comment on lines +27 to +41
// Get user's country from IP
useEffect(() => {
fetch('https://ipapi.co/json/')
.then(res => res.json())
.then(data => {
if (data.country_code_iso3) {
setUserCountry(data.country_code_iso3)
}
})
.catch(() => {
// Fallback to India if detection fails
setUserCountry('IND')
})
}, [])

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid client IP calls + remove hardcoded 'IND' fallback.

  • Third-party IP lookups on mount have privacy/compliance risks and can be blocked/slow.
  • Hardcoding India contradicts prior guidance to avoid hardcoded IDs (per repository learnings).

Apply this change to only fetch when the field is empty, add abort, and drop the default-to-IND:

-	// Get user's country from IP
-	useEffect(() => {
-		fetch('https://ipapi.co/json/')
-			.then(res => res.json())
-			.then(data => {
-				if (data.country_code_iso3) {
-					setUserCountry(data.country_code_iso3)
-				}
-			})
-			.catch(() => {
-				// Fallback to India if detection fails
-				setUserCountry('IND')
-			})
-	}, [])
+	// Prefill user's country via IP (best-effort) only if empty
+	useEffect(() => {
+		if (form.getValues(name)) return
+		const controller = new AbortController()
+		fetch('https://ipapi.co/json/', {signal: controller.signal})
+			.then(res => res.json())
+			.then(data => {
+				if (data?.country_code_iso3) setUserCountry(data.country_code_iso3)
+			})
+			.catch(() => {
+				// silent: no default country
+			})
+		return () => controller.abort()
+	}, [form, name])

If IP prefill must remain, gate it behind a feature flag and update the privacy notice.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Get user's country from IP
useEffect(() => {
fetch('https://ipapi.co/json/')
.then(res => res.json())
.then(data => {
if (data.country_code_iso3) {
setUserCountry(data.country_code_iso3)
}
})
.catch(() => {
// Fallback to India if detection fails
setUserCountry('IND')
})
}, [])
// Prefill user's country via IP (best-effort) only if empty
useEffect(() => {
if (form.getValues(name)) return
const controller = new AbortController()
fetch('https://ipapi.co/json/', { signal: controller.signal })
.then(res => res.json())
.then(data => {
if (data?.country_code_iso3) setUserCountry(data.country_code_iso3)
})
.catch(() => {
// silent: no default country
})
return () => controller.abort()
}, [form, name])
🤖 Prompt for AI Agents
In components/resume/editors/shared/CountrySelect.tsx around lines 27 to 41, the
current useEffect always calls a third‑party IP lookup on mount and falls back
to hardcoded 'IND'; change it to (1) only perform the fetch if the country field
is currently empty, (2) use an AbortController and cancel the request in the
cleanup to avoid leaks, (3) remove the hardcoded fallback (do not set 'IND' on
error), and (4) if IP prefill is required, gate the fetch behind a feature flag
and ensure the privacy notice is updated accordingly; implement these changes so
the effect is conditional, abortable, and no longer writes a default country on
failure.

Comment on lines +13 to +16
showAnimation?: boolean
}

const ResumeViewer = ({resume, resumeRef, className}: ResumeViewerProps) => {
const ResumeViewer = ({resume, resumeRef, className, showAnimation = true}: ResumeViewerProps) => {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Honor reduced-motion when defaulting showAnimation

Defaulting to true ignores user OS preference. Derive the effective flag to auto-disable animations when reduced-motion is set, while still allowing explicit overrides.

-const ResumeViewer = ({resume, resumeRef, className, showAnimation = true}: ResumeViewerProps) => {
+const ResumeViewer = (props: ResumeViewerProps) => {
+  const {resume, resumeRef, className, showAnimation} = props
+  const prefersReduced =
+    typeof window !== 'undefined' &&
+    window.matchMedia('(prefers-reduced-motion: reduce)').matches
+  const enableAnimation = (showAnimation ?? true) && !prefersReduced

Then replace usages of showAnimation below with enableAnimation.

🤖 Prompt for AI Agents
In components/resume/ResumeViewer.tsx around lines 13 to 16, the prop default
showAnimation=true ignores the user's reduced-motion OS preference; update the
component to compute an enableAnimation boolean that respects reduced-motion
(e.g., use window.matchMedia('(prefers-reduced-motion: reduce)') or a React hook
to detect it) so that enableAnimation = showAnimation when showAnimation is
explicitly provided, otherwise false when reduced-motion is true and true when
not. Replace the defaulted prop logic (remove showAnimation default) and use
enableAnimation for all downstream animation checks and rendering decisions,
ensuring explicit prop overrides still work.

Comment on lines +5 to +8
**We are not currently accepting external contributions to this project.**

Letraz is currently being developed by our internal team, and we are not seeking outside contributors at this time.

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add security disclosure and issues/feedback channels.

Even if PRs aren’t accepted, you should tell external users how to responsibly report security vulnerabilities and where to file bugs/feedback. This avoids public disclosure in PRs and reduces triage noise.

Apply:

 Letraz is currently being developed by our internal team, and we are not seeking outside contributors at this time.
+
+## Reporting Security Vulnerabilities
+If you discover a security issue, please do not open a public issue. Instead, email us at [hello@letraz.app](mailto:hello@letraz.app) with details and a way to reproduce. We will acknowledge receipt within 3 business days.
+
+## Feedback and Bug Reports
+While we’re not accepting external code contributions, we welcome feedback and bug reports. Please use the repository’s Issues tab to open a ticket with steps to reproduce and expected behavior.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
**We are not currently accepting external contributions to this project.**
Letraz is currently being developed by our internal team, and we are not seeking outside contributors at this time.
**We are not currently accepting external contributions to this project.**
Letraz is currently being developed by our internal team, and we are not seeking outside contributors at this time.
## Reporting Security Vulnerabilities
If you discover a security issue, please do not open a public issue. Instead, email us at [hello@letraz.app](mailto:hello@letraz.app) with details and a way to reproduce. We will acknowledge receipt within 3 business days.
## Feedback and Bug Reports
While we’re not accepting external code contributions, we welcome feedback and bug reports. Please use the repository’s Issues tab to open a ticket with steps to reproduce and expected behavior.
🤖 Prompt for AI Agents
In CONTRIBUTING.md around lines 5 to 8, the file currently only states that
external contributions are not accepted; add a short Security Policy and
Issue/Feedback section that tells external users how to responsibly report
security vulnerabilities (eg. an email like security@yourdomain or a link to a
private vulnerability reporting form) and where to file bugs/feedback (eg. a
link to the project’s issue tracker or a dedicated feedback email), include
guidance to avoid posting vulnerabilities publicly (do not open PRs for security
issues), specify expected response/triage timeframe, and provide contact/PGP key
info if needed.

@pingSubhajit pingSubhajit changed the base branch from main to stg/main October 16, 2025 06:26
Base automatically changed from stg/main to main October 27, 2025 14:27
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.

5 participants