Skip to content

Commit

Permalink
Add company data script, metadata file, and turbo.json env updates (#179
Browse files Browse the repository at this point in the history
)
  • Loading branch information
thomasdavis authored Feb 8, 2025
1 parent f6f56f1 commit 17f6e83
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 39 deletions.
115 changes: 85 additions & 30 deletions apps/registry/app/[username]/jobs-graph/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,14 @@ export default function Jobs({ params }) {
const highlightText = useCallback((text, searchText) => {
if (!searchText || !text) return text;
const parts = text.toString().split(new RegExp(`(${searchText})`, 'gi'));
return parts.map((part, index) =>
part.toLowerCase() === searchText.toLowerCase() ?
<span key={index} className="bg-yellow-200">{part}</span> : part
return parts.map((part, index) =>
part.toLowerCase() === searchText.toLowerCase() ? (
<span key={index} className="bg-yellow-200">
{part}
</span>
) : (
part
)
);
}, []);

Expand Down Expand Up @@ -248,9 +253,18 @@ export default function Jobs({ params }) {
data: {
label: isResume ? (
<div className="resume-node-content">
<svg className="resume-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
<svg
className="resume-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
<span>Your Resume</span>
</div>
Expand All @@ -260,29 +274,32 @@ export default function Jobs({ params }) {
{jobData?.title || 'Unknown Position'}
</div>
<div className="company-name">
<svg className="company-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5}
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
<svg
className="company-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
/>
</svg>
{jobData?.company || 'Unknown Company'}
</div>

<div className="job-meta">
<div className="meta-pills">
{jobData?.type && (
<div className="meta-pill type">
{jobData.type}
</div>
<div className="meta-pill type">{jobData.type}</div>
)}
{jobData?.remote && (
<div className="meta-pill remote">
{jobData.remote}
</div>
<div className="meta-pill remote">{jobData.remote}</div>
)}
{jobData?.salary && (
<div className="meta-pill salary">
{jobData.salary}
</div>
<div className="meta-pill salary">{jobData.salary}</div>
)}
</div>
</div>
Expand Down Expand Up @@ -525,10 +542,20 @@ export default function Jobs({ params }) {
<div className="flex justify-between items-start">
<div>
<h3 className="text-xl font-bold text-gray-900">
{filterText ? highlightText(selectedNode.data.jobInfo.title, filterText) : selectedNode.data.jobInfo.title}
{filterText
? highlightText(
selectedNode.data.jobInfo.title,
filterText
)
: selectedNode.data.jobInfo.title}
</h3>
<p className="text-indigo-600 font-medium mt-1">
{filterText ? highlightText(selectedNode.data.jobInfo.company, filterText) : selectedNode.data.jobInfo.company}
{filterText
? highlightText(
selectedNode.data.jobInfo.company,
filterText
)
: selectedNode.data.jobInfo.company}
</p>
<div className="flex gap-3 mt-2">
{selectedNode.data.jobInfo.type && (
Expand Down Expand Up @@ -612,7 +639,12 @@ export default function Jobs({ params }) {

{selectedNode.data.jobInfo.description && (
<div className="text-gray-600 text-sm leading-relaxed">
{filterText ? highlightText(selectedNode.data.jobInfo.description, filterText) : selectedNode.data.jobInfo.description}
{filterText
? highlightText(
selectedNode.data.jobInfo.description,
filterText
)
: selectedNode.data.jobInfo.description}
</div>
)}

Expand All @@ -625,11 +657,19 @@ export default function Jobs({ params }) {
<div className="flex flex-wrap gap-1.5">
{selectedNode.data.jobInfo.skills.map(
(skill, index) => (
<div key={index} className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">
{filterText ? highlightText(skill.name, filterText) : skill.name}
<div
key={index}
className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
>
{filterText
? highlightText(skill.name, filterText)
: skill.name}
{skill.level && (
<span className="ml-1 text-gray-400">
{filterText ? highlightText(skill.level, filterText) : skill.level}
{' '}
{filterText
? highlightText(skill.level, filterText)
: skill.level}
</span>
)}
</div>
Expand All @@ -649,7 +689,9 @@ export default function Jobs({ params }) {
{selectedNode.data.jobInfo.qualifications.map(
(qual, index) => (
<li key={index}>
{filterText ? highlightText(qual, filterText) : qual}
{filterText
? highlightText(qual, filterText)
: qual}
</li>
)
)}
Expand All @@ -666,9 +708,18 @@ export default function Jobs({ params }) {
className="inline-flex items-center gap-1.5 rounded-md px-4 py-2 text-sm font-medium bg-blue-600 text-white hover:bg-blue-700 shadow-sm transition-colors"
>
View Job Details
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
<svg
className="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
</a>
</div>
Expand Down Expand Up @@ -701,7 +752,11 @@ export default function Jobs({ params }) {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at center, rgba(37, 99, 235, 0.1) 0%, transparent 70%);
background: radial-gradient(
circle at center,
rgba(37, 99, 235, 0.1) 0%,
transparent 70%
);
animation: pulse 3s ease-in-out infinite;
}
Expand Down
68 changes: 61 additions & 7 deletions apps/registry/app/providers/ResumeProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function useResume() {
}

export function ResumeProvider({ children, targetUsername }) {
const [session, setSession] = useState(null);
const [, setSession] = useState(null);
const [resume, setResume] = useState(null);
const [gistId, setGistId] = useState(null);
const [loading, setLoading] = useState(true);
Expand Down Expand Up @@ -170,11 +170,38 @@ export function ResumeProvider({ children, targetUsername }) {

const updateGist = async (resumeContent) => {
try {
if (!session?.provider_token) {
throw new Error('No GitHub access token available');
const {
data: { session: currentSession },
} = await supabase.auth.getSession();

if (!currentSession?.provider_token) {
// Try to get a fresh token
try {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
scopes: 'gist',
redirectTo: window.location.origin,
queryParams: {
access_type: 'offline',
prompt: 'consent',
},
},
});

if (error) throw error;

// Wait for redirect
return;
} catch (error) {
console.error('GitHub authentication error:', error);
throw new Error(
'Failed to authenticate with GitHub. Please try again.'
);
}
}

const octokit = new Octokit({ auth: session.provider_token });
const octokit = new Octokit({ auth: currentSession.provider_token });

if (gistId) {
await octokit.rest.gists.update({
Expand Down Expand Up @@ -210,11 +237,38 @@ export function ResumeProvider({ children, targetUsername }) {

const createGist = async (sampleResume) => {
try {
if (!session?.provider_token) {
throw new Error('No GitHub access token available');
const {
data: { session: currentSession },
} = await supabase.auth.getSession();

if (!currentSession?.provider_token) {
// Try to get a fresh token
try {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
scopes: 'gist',
redirectTo: window.location.origin,
queryParams: {
access_type: 'offline',
prompt: 'consent',
},
},
});

if (error) throw error;

// Wait for redirect
return;
} catch (error) {
console.error('GitHub authentication error:', error);
throw new Error(
'Failed to authenticate with GitHub. Please try again.'
);
}
}

const octokit = new Octokit({ auth: session.provider_token });
const octokit = new Octokit({ auth: currentSession.provider_token });
const { data } = await octokit.rest.gists.create({
files: {
[RESUME_GIST_NAME]: {
Expand Down
80 changes: 79 additions & 1 deletion apps/registry/app/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,74 @@ export default function SettingsPage() {
<p>{username}</p>
</div>
)}
<div>
<h2 className="font-semibold">GitHub Connection Status</h2>
{session.user.identities?.some(
(identity: any) => identity.provider === 'github'
) ? (
<div className="space-y-2">
<p className="text-green-600">✓ Connected to GitHub</p>
<p className="text-sm text-gray-600">
Access Token Available:{' '}
{session.user.identities?.find(
(identity: any) => identity.provider === 'github'
)?.access_token
? 'Yes'
: 'No'}
</p>
<div className="text-sm text-gray-600">
<p>Provider Token: {session.provider_token ? 'Yes' : 'No'}</p>
{session.provider_token && (
<p className="text-xs">
Token: {session.provider_token.substring(0, 8)}...
{session.provider_token.substring(
session.provider_token.length - 8
)}
</p>
)}
<p>
App Metadata Token:{' '}
{session.user.app_metadata?.provider_token ? 'Yes' : 'No'}
</p>
<p>
Identity Token:{' '}
{session.user.identities?.find(
(identity: any) => identity.provider === 'github'
)?.provider_token
? 'Yes'
: 'No'}
</p>
</div>
{!session.user.identities?.find(
(identity: any) => identity.provider === 'github'
)?.access_token && (
<button
onClick={async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
scopes: 'gist',
redirectTo: window.location.origin + '/settings',
queryParams: {
access_type: 'offline',
prompt: 'consent',
},
},
});
if (error) {
console.error('OAuth error:', error);
}
}}
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Reconnect GitHub with Gist Access
</button>
)}
</div>
) : (
<p className="text-red-600">Not connected to GitHub</p>
)}
</div>
<div>
<h2 className="font-semibold">User ID</h2>
<p>{session.user.id}</p>
Expand All @@ -60,7 +128,17 @@ export default function SettingsPage() {
<div className="mt-8">
<h2 className="font-semibold mb-2">Debug Information</h2>
<div className="bg-gray-50 p-4 rounded-md">
<h3 className="font-medium">User Metadata</h3>
<h3 className="font-medium">GitHub Identity</h3>
<pre className="text-sm overflow-auto">
{JSON.stringify(
session.user.identities?.find(
(identity: any) => identity.provider === 'github'
),
null,
2
)}
</pre>
<h3 className="font-medium mt-2">User Metadata</h3>
<pre className="text-sm overflow-auto">
{JSON.stringify(session.user.user_metadata, null, 2)}
</pre>
Expand Down
Loading

0 comments on commit 17f6e83

Please sign in to comment.