mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-27 02:14:50 +10:00
feat(jobs): add job listings with AI-powered resume tailoring (#2788)
* feat: add job listings feature with JSearch API integration, resume tailoring, and per-user rate limiting * feat(jobs): add search filters UI, filter helper functions with tests, and job_search_quota DB migration * feat(jobs): add pagination with 30 results per page and prev/next navigation * refactor(job-detail): Adjust sheet width and scroll area height * feat(ai): Add resume tailoring feature and prompt * refactor(ai): Revise tailoring prompts and schema for full skill rewrite * feat(ai): Add reference tailoring and output sanitization * feat(testing): Add Vitest testing framework * fix: address PR review - atomic rate limiting, calendar-month quota, skill sync warning, gitignore routeTree.gen.ts * feat(jobs): Add location filter to job listings * feat(job-listings): Add DOCX document generation * feat(job-listings): Enable search by location and on Enter key * feat(job-listings): Split location filter into city, state, and country * feat(jobs): Implement job search adapter and JSearch * Update 'locale/' directory * feat(resume): Simplify filename generation and add tests * fix(JSearch): reduce JSearch API usage to 1 request per search to prevent quota exhaustion * fix(JSearch): Displayed quota amounts on Job Search functionality and settings fixed to pull from RapidAPI/JSearch response * fix(internal rate limit): Removed internal rate limit and .env.example addition, cloud based implementation handles. * style(job-filters): Adjust layout of switch filters * fix(typecheck): Fixed typecheck issues introduced to sync with origin * feat(jobs): Enhance tailor dialog with apply link and tags * feat(locale files): updated locale files with the latest build * feat(jobs): Add job search provider and integrate testing functionality - Introduced `createJobSearchProvider` function to instantiate a JSearchProvider. - Enhanced job search provider with methods for searching jobs, retrieving job details, and testing connection. - Updated `vite.config.ts` to include new testing configurations and plugins. - Added new dependencies in `package.json` for testing and document generation. - Removed obsolete `vitest.config.ts` file. - Improved job search provider tests for better coverage and reliability. * refactor: Update job search routes and remove obsolete test configurations - Removed the test configuration from `vite.config.ts`. - Updated localization files to reflect changes in job search routes, renaming references from `jobs` to `job-search` across multiple languages. - Adjusted autofix workflow to run formatting without the `--fix` flag for better control over code style adjustments. * chore: Update dependencies and improve animation performance - Added `jsdom` as a new dependency in `package.json`. - Updated `vite-plus` and `vitest` to the latest versions for better compatibility. - Enhanced animation components with `willChange` styles to optimize rendering performance. - Adjusted various UI components to improve responsiveness and visual effects. - Removed obsolete job details functionality from the job search provider and related tests. * chore(locales): Update localization files for job search improvements - Modified job search related strings to remove references to "this month" for a more concise format. - Updated file references in localization entries to reflect changes in the job search component structure. - Added new strings for API usage, quota remaining, and job fetching error messages across multiple languages. - Removed obsolete "Monthly Usage" string from localization files. * chore(dependencies): Update @typescript/native-preview to version 7.0.0-dev.20260319.1 --------- Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
This commit is contained in:
@@ -29,7 +29,8 @@ export function PasswordSection() {
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3, delay: 0.1 }}
|
||||
transition={{ duration: 0.2, delay: 0.1, ease: "easeOut" }}
|
||||
style={{ willChange: "transform, opacity" }}
|
||||
className="flex items-center justify-between gap-x-4"
|
||||
>
|
||||
<h2 className="flex items-center gap-x-3 text-base font-medium">
|
||||
@@ -39,21 +40,35 @@ export function PasswordSection() {
|
||||
|
||||
{match(hasPassword)
|
||||
.with(true, () => (
|
||||
<Button variant="outline" onClick={handleUpdatePassword}>
|
||||
<PencilSimpleLineIcon />
|
||||
<Trans>Update Password</Trans>
|
||||
</Button>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button variant="outline" onClick={handleUpdatePassword}>
|
||||
<PencilSimpleLineIcon />
|
||||
<Trans>Update Password</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
.with(false, () => (
|
||||
<Button
|
||||
variant="outline"
|
||||
nativeButton={false}
|
||||
render={
|
||||
<Link to="/auth/forgot-password">
|
||||
<Trans>Set Password</Trans>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
nativeButton={false}
|
||||
render={
|
||||
<Link to="/auth/forgot-password">
|
||||
<Trans>Set Password</Trans>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
</motion.div>
|
||||
))
|
||||
.exhaustive()}
|
||||
</motion.div>
|
||||
|
||||
@@ -40,7 +40,8 @@ export function SocialProviderSection({ provider, name, animationDelay = 0 }: So
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3, delay: animationDelay }}
|
||||
transition={{ duration: 0.2, delay: animationDelay, ease: "easeOut" }}
|
||||
style={{ willChange: "transform, opacity" }}
|
||||
>
|
||||
<Separator />
|
||||
|
||||
@@ -52,16 +53,30 @@ export function SocialProviderSection({ provider, name, animationDelay = 0 }: So
|
||||
|
||||
{match(isConnected)
|
||||
.with(true, () => (
|
||||
<Button variant="outline" onClick={handleUnlink}>
|
||||
<LinkBreakIcon />
|
||||
<Trans>Disconnect</Trans>
|
||||
</Button>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button variant="outline" onClick={handleUnlink}>
|
||||
<LinkBreakIcon />
|
||||
<Trans>Disconnect</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
.with(false, () => (
|
||||
<Button variant="outline" onClick={handleLink}>
|
||||
<LinkIcon />
|
||||
<Trans>Connect</Trans>
|
||||
</Button>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button variant="outline" onClick={handleLink}>
|
||||
<LinkIcon />
|
||||
<Trans>Connect</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
.exhaustive()}
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,8 @@ export function TwoFactorSection() {
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3, delay: 0.2 }}
|
||||
transition={{ duration: 0.2, delay: 0.2, ease: "easeOut" }}
|
||||
style={{ willChange: "transform, opacity" }}
|
||||
>
|
||||
<Separator />
|
||||
|
||||
@@ -45,16 +46,30 @@ export function TwoFactorSection() {
|
||||
|
||||
{match(hasTwoFactor)
|
||||
.with(true, () => (
|
||||
<Button variant="outline" onClick={handleTwoFactorAction}>
|
||||
<ToggleLeftIcon />
|
||||
<Trans>Disable 2FA</Trans>
|
||||
</Button>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button variant="outline" onClick={handleTwoFactorAction}>
|
||||
<ToggleLeftIcon />
|
||||
<Trans>Disable 2FA</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
.with(false, () => (
|
||||
<Button variant="outline" onClick={handleTwoFactorAction}>
|
||||
<ToggleRightIcon />
|
||||
<Trans>Enable 2FA</Trans>
|
||||
</Button>
|
||||
<motion.div
|
||||
whileHover={{ y: -1, scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
transition={{ duration: 0.14, ease: "easeOut" }}
|
||||
style={{ willChange: "transform" }}
|
||||
>
|
||||
<Button variant="outline" onClick={handleTwoFactorAction}>
|
||||
<ToggleRightIcon />
|
||||
<Trans>Enable 2FA</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
.exhaustive()}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user