Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

job recommendation graph #172

Merged
merged 49 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
6fd17a1
asd
thomasdavis Dec 21, 2024
2a9fb19
asd
thomasdavis Dec 22, 2024
a8a7253
asd
thomasdavis Dec 22, 2024
2908c8e
asd
thomasdavis Dec 22, 2024
c057830
asd
thomasdavis Dec 22, 2024
5d67749
wip
thomasdavis Dec 23, 2024
72f1852
wip
thomasdavis Jan 8, 2025
ef897a7
wip
thomasdavis Jan 8, 2025
4235f02
wip
thomasdavis Jan 8, 2025
2581f63
wip
thomasdavis Jan 8, 2025
de2b4d6
wip
thomasdavis Jan 8, 2025
c1bfe3c
wip
thomasdavis Jan 8, 2025
9f8e4fd
wip
thomasdavis Jan 8, 2025
1301458
wip
thomasdavis Jan 8, 2025
440e0bb
wip
thomasdavis Jan 8, 2025
5714af5
wip
thomasdavis Jan 8, 2025
234a3ed
wip
thomasdavis Jan 8, 2025
4342629
wip
thomasdavis Jan 8, 2025
d5e486b
wip
thomasdavis Jan 8, 2025
91d368d
wip
thomasdavis Jan 8, 2025
32c3144
wip
thomasdavis Jan 8, 2025
78a2766
wip
thomasdavis Jan 8, 2025
12946f2
wip
thomasdavis Jan 9, 2025
3403a61
wip
thomasdavis Jan 9, 2025
7fb85bf
wip
thomasdavis Jan 9, 2025
2c14531
wip
thomasdavis Jan 9, 2025
f4c65fb
wip
thomasdavis Jan 9, 2025
03fd05d
wip
thomasdavis Jan 9, 2025
e0500fb
wip
thomasdavis Jan 9, 2025
b77b7e9
wip
thomasdavis Jan 9, 2025
f2710ab
wip
thomasdavis Jan 9, 2025
03d28e7
wip
thomasdavis Jan 9, 2025
755bfca
wip
thomasdavis Jan 9, 2025
4909768
wip
thomasdavis Jan 9, 2025
19222f6
asd
thomasdavis Jan 12, 2025
be2d7b5
asd
thomasdavis Jan 12, 2025
8964c85
asd
thomasdavis Jan 12, 2025
a1741ef
asd
thomasdavis Jan 12, 2025
c003633
asd
thomasdavis Jan 12, 2025
c1ab4a6
asd
thomasdavis Jan 12, 2025
f9d97ef
asd
thomasdavis Jan 12, 2025
b34a807
asd
thomasdavis Jan 12, 2025
b3b79a2
asd
thomasdavis Jan 12, 2025
fc4a25f
asd
thomasdavis Jan 12, 2025
1f296cf
asd
thomasdavis Jan 12, 2025
58336ac
asd
thomasdavis Jan 12, 2025
805798f
asd
thomasdavis Jan 12, 2025
d6cdbe3
asd
thomasdavis Jan 12, 2025
19f51c8
asd
thomasdavis Jan 12, 2025
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
198 changes: 198 additions & 0 deletions apps/registry/app/[username]/jobs-graph/JobList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import React, { useState } from 'react';
import {
MapPin,
Building,
Calendar,
DollarSign,
BriefcaseIcon,
Globe,
CheckCircle,
Star,
} from 'lucide-react';
import Link from 'next/link';

const JobDescription = ({ job, makeCoverletter }) => {
const [expanded, setExpanded] = useState(false);
console.log({ job });
return (
<div
className="p-6 bg-white shadow-lg rounded-lg transition-transform transform hover:scale-105 cursor-pointer"
onClick={() => setExpanded(!expanded)}
>
Comment on lines +14 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove debug console.log and add prop types validation

  1. Remove the debug console.log statement
  2. Consider using TypeScript or PropTypes for prop validation
  3. The click handler might interfere with button clicks within the component
-  console.log({ job });

Also, consider stopping event propagation for button clicks to prevent unintended expansions.

📝 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 JobDescription = ({ job, makeCoverletter }) => {
const [expanded, setExpanded] = useState(false);
console.log({ job });
return (
<div
className="p-6 bg-white shadow-lg rounded-lg transition-transform transform hover:scale-105 cursor-pointer"
onClick={() => setExpanded(!expanded)}
>
const JobDescription = ({ job, makeCoverletter }) => {
const [expanded, setExpanded] = useState(false);
return (
<div
className="p-6 bg-white shadow-lg rounded-lg transition-transform transform hover:scale-105 cursor-pointer"
onClick={() => setExpanded(!expanded)}
>
🧰 Tools
🪛 GitHub Actions: CI

[error] Lint command failed with exit code 1

<header className="mb-4">
<h1 className="text-2xl font-bold text-gray-800">
{job.title || 'Not available'}
</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-gray-600 mt-2">
<div className="flex items-center">
<Building className="w-5 h-5 mr-2" />
<span>{job.company || 'Not available'}</span>
</div>
<div className="flex items-center">
<DollarSign className="w-5 h-5 mr-2 text-warning-500" />
<span>
{job.salary
? `$${Number(job.salary).toLocaleString()}/year`
: 'Not available'}
</span>
</div>
<div className="flex items-center">
<MapPin className="w-5 h-5 mr-2 text-secondary-500" />
<span>
{job.location
? `${job.location.city}, ${job.location.countryCode}`
: 'Not available'}
</span>
</div>
<div className="flex items-center">
<BriefcaseIcon className="w-5 h-5 mr-2 text-accent-500" />
<span>{job.experience || 'Not available'}</span>
</div>
<div className="flex items-center">
<Globe className="w-5 h-5 mr-2 text-accent-500" />
<span>Remote - {job.remote || 'Not available'}</span>
</div>
<div className="flex items-center">
<Calendar className="w-5 h-5 mr-2 text-success-500" />
<span>{job.date || 'Not available'}</span>
</div>
<div className="text-gray-600 col-span-full">
{expanded ? (
<p>{job.description || 'Not available'}</p>
) : (
<p>
{job.description
? job.description.slice(0, 100) + '...'
: 'Not available'}
</p>
)}
</div>
</div>
</header>
{expanded && (
<div className="mt-4">
<div className="mb-6">
<h2 className="text-2xl font-semibold mb-3 text-gray-800">
Responsibilities
</h2>
<ul className="list-none">
{job.responsibilities?.length ? (
job.responsibilities.map((resp, index) => (
<li key={index} className="flex items-start mb-2">
<CheckCircle className="w-5 h-5 mr-2 text-success-500 flex-shrink-0 mt-1" />
<span>{resp}</span>
</li>
))
) : (
<p>Not available</p>
)}
</ul>
</div>

<div className="mb-6">
<h2 className="text-2xl font-semibold mb-3 text-gray-800">
Qualifications
</h2>
<ul className="list-none">
{job.qualifications?.length ? (
job.qualifications.map((qual, index) => (
<li key={index} className="flex items-start mb-2">
<CheckCircle className="w-5 h-5 mr-2 text-secondary-500 flex-shrink-0 mt-1" />
<span>{qual}</span>
</li>
))
) : (
<p>Not available</p>
)}
</ul>
</div>

<div className="mb-6">
<h2 className="text-2xl font-semibold mb-3 text-gray-800">
Skills
</h2>
{job.skills?.length ? (
job.skills.map((skill, index) => (
<div key={index} className="mb-4">
<h3 className="text-xl font-semibold text-gray-700">
{skill.name}
</h3>
<div className="flex items-center mb-2">
<Star className="w-5 h-5 mr-2 text-warning-500" />
<span>{skill.level}</span>
</div>
<div className="flex flex-wrap gap-2">
{skill.keywords?.length ? (
skill.keywords.map((keyword, kidx) => (
<span
key={kidx}
className="px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm"
>
{keyword}
</span>
))
) : (
<p>Not available</p>
)}
</div>
</div>
))
) : (
<p>Not available</p>
)}
</div>
<div className="mt-4 flex gap-4">
<button
className="bg-secondary-500 text-white py-2 px-4 rounded hover:bg-secondary-700 transition-colors duration-200"
onClick={() => makeCoverletter(job.raw)}
>
Make Cover Letter
</button>
<a
href={job.raw?.url || '#'}
target="_blank"
rel="noopener noreferrer"
className="bg-gray-200 text-gray-700 py-2 px-4 rounded hover:bg-gray-300 transition-colors duration-200"
>
View Original Job
</a>

<Link
href={`/jobs/${job.raw.uuid}`}
target="_blank"
rel="noopener noreferrer"
className="bg-gray-200 text-gray-700 py-2 px-4 rounded hover:bg-gray-300 transition-colors duration-200"
>
View Job Candiates
</Link>
</div>
Comment on lines +160 to +168
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null checks and improve accessibility

  1. Add null check for job.raw.uuid
  2. Add aria-label for better accessibility
 <Link
-  href={`/jobs/${job.raw.uuid}`}
+  href={job.raw?.uuid ? `/jobs/${job.raw.uuid}` : '#'}
+  aria-label="View job candidates"
   target="_blank"
   rel="noopener noreferrer"
   className="bg-gray-200 text-gray-700 py-2 px-4 rounded hover:bg-gray-300 transition-colors duration-200"
 >
   View Job Candiates
 </Link>

Also, fix the typo in "Candiates" → "Candidates"

📝 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
<Link
href={`/jobs/${job.raw.uuid}`}
target="_blank"
rel="noopener noreferrer"
className="bg-gray-200 text-gray-700 py-2 px-4 rounded hover:bg-gray-300 transition-colors duration-200"
>
View Job Candiates
</Link>
</div>
<Link
href={job.raw?.uuid ? `/jobs/${job.raw.uuid}` : '#'}
aria-label="View job candidates"
target="_blank"
rel="noopener noreferrer"
className="bg-gray-200 text-gray-700 py-2 px-4 rounded hover:bg-gray-300 transition-colors duration-200"
>
View Job Candidates
</Link>
</div>
🧰 Tools
🪛 GitHub Actions: CI

[error] Lint command failed with exit code 1

</div>
)}
</div>
);
};

const JobList = ({ jobs, makeCoverletter }) => {
const validJobs = jobs?.filter(
(job) => job.gpt_content && job.gpt_content !== 'FAILED'
);
const fullJobs = validJobs?.map((job) => {
const fullJob = JSON.parse(job.gpt_content);
fullJob.raw = job;
return fullJob;
});

Comment on lines +175 to +184
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for JSON parsing

The current implementation could throw runtime errors if job.gpt_content contains invalid JSON.

 const fullJobs = validJobs?.map((job) => {
-    const fullJob = JSON.parse(job.gpt_content);
-    fullJob.raw = job;
-    return fullJob;
+    try {
+      const fullJob = JSON.parse(job.gpt_content);
+      fullJob.raw = job;
+      return fullJob;
+    } catch (error) {
+      console.error(`Failed to parse job content: ${error}`);
+      return null;
+    }
-  });
+  }).filter(Boolean);
📝 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 JobList = ({ jobs, makeCoverletter }) => {
const validJobs = jobs?.filter(
(job) => job.gpt_content && job.gpt_content !== 'FAILED'
);
const fullJobs = validJobs?.map((job) => {
const fullJob = JSON.parse(job.gpt_content);
fullJob.raw = job;
return fullJob;
});
const JobList = ({ jobs, makeCoverletter }) => {
const validJobs = jobs?.filter(
(job) => job.gpt_content && job.gpt_content !== 'FAILED'
);
const fullJobs = validJobs?.map((job) => {
try {
const fullJob = JSON.parse(job.gpt_content);
fullJob.raw = job;
return fullJob;
} catch (error) {
console.error(`Failed to parse job content: ${error}`);
return null;
}
}).filter(Boolean);
🧰 Tools
🪛 GitHub Actions: CI

[error] Lint command failed with exit code 1

return (
<div className="flex flex-col gap-5">
{fullJobs?.map((job, index) => (
<JobDescription
key={index}
job={job}
makeCoverletter={makeCoverletter}
/>
))}
</div>
);
};

export default JobList;
5 changes: 5 additions & 0 deletions apps/registry/app/[username]/jobs-graph/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use client';

export default function Home({ children }) {
return <>{children}</>;
}
Loading
Loading