Skip to content

Commit 0b9feef

Browse files
committed
talent pool
1 parent 8ebec72 commit 0b9feef

File tree

10 files changed

+539
-7
lines changed

10 files changed

+539
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [0.1.5] - 2025-09-20
4+
### Added
5+
- talent pool options
6+
37
## [0.1.4] - 2025-09-18
48
### Added
59
- printable report

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@bounteer/page",
33
"type": "module",
4-
"version": "0.1.4",
4+
"version": "0.1.5",
55
"private": true,
66
"scripts": {
77
"dev": "astro dev",

src/components/Header.astro

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ const allPages = [
4141
class="text-secondary-600 hover:text-accent-600 font-medium transition-colors"
4242
>Role Fit Index</a
4343
>
44+
<a
45+
href="/talent-pool"
46+
class="text-secondary-600 hover:text-accent-600 font-medium transition-colors"
47+
>Talent Pool</a
48+
>
4449
<a
4550
href="/contact"
4651
class="text-secondary-600 hover:text-accent-600 font-medium transition-colors"
@@ -115,6 +120,11 @@ const allPages = [
115120
class="block px-4 py-2 text-sm text-secondary-700 hover:bg-secondary-100"
116121
>Role Fit Index</a
117122
>
123+
<a
124+
href="/talent-pool"
125+
class="block px-4 py-2 text-sm text-secondary-700 hover:bg-secondary-100"
126+
>Talent Pool</a
127+
>
118128
<a
119129
href="/contact"
120130
class="block px-4 py-2 text-sm text-secondary-700 hover:bg-secondary-100"

src/components/Products.astro

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const stages = [
88
subtitle: "Instant, AI-powered JD to CV match analysis.",
99
launchDate: "September 2025",
1010
currentStage: "Beta Release",
11+
tagColor: "bg-emerald-100 text-emerald-700",
1112
features: [
1213
"Upload CV & paste a job description (multiple formats)",
1314
"Overall match score with confidence band",
@@ -19,16 +20,36 @@ const stages = [
1920
buttonLabel: "Try Role Fit Index Now",
2021
buttonHref: "/role-fit-index",
2122
},
23+
{
24+
stage: "Stage 1.5",
25+
title: "Bounteer Talent Pool",
26+
subtitle:
27+
"Opt-in to get discovered by recruiters — showcase your top match scores.",
28+
launchDate: "September 2025",
29+
currentStage: "Beta Release",
30+
tagColor: "bg-blue-100 text-blue-700",
31+
features: [
32+
"Join a curated directory of top-scoring candidates from RFI",
33+
"Showcase your strengths, skills, and high match scores to recruiters",
34+
"Control what you share — privacy-first and opt-in only",
35+
"Get contacted directly by companies looking for candidates like you",
36+
"Stay updated when your profile is viewed or shortlisted",
37+
"Boost your visibility by improving your match scores over time",
38+
],
39+
buttonLabel: "Join Talent Pool",
40+
buttonHref: "/talent-pool",
41+
},
2242
{
2343
stage: "Stage 2",
2444
title: "Bounteer Marketplace",
2545
subtitle: "Quality-first referral bounties with transparent payouts.",
2646
launchDate: "2026",
2747
currentStage: "In Development",
48+
tagColor: "bg-orange-100 text-orange-700",
2849
features: [
2950
"Post roles with tiered bounties & clear acceptance criteria",
3051
"Verified referrers submit candidates with one link",
31-
"Built-in screening powered by Role Fit Index",
52+
"Built-in screening powered by RFI",
3253
"Reputation & anti-spam quality gates",
3354
"Dashboard for pipeline, payouts, and ROI",
3455
"Optional escrow & milestone-based releases",
@@ -40,7 +61,7 @@ const stages = [
4061
---
4162

4263
<section class="py-12">
43-
<div class="container-custom grid md:grid-cols-2 gap-6">
64+
<div class="container-custom grid md:grid-cols-3 gap-6">
4465
{
4566
stages.map((stage) => (
4667
<ProductCard
@@ -53,6 +74,7 @@ const stages = [
5374
features={stage.features}
5475
buttonLabel={stage.buttonLabel}
5576
buttonHref={stage.buttonHref}
77+
tagColor={stage.tagColor}
5678
/>
5779
))
5880
}

src/components/interactive/ProductCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface ProductCardProps {
1919
features: string[];
2020
buttonLabel: string;
2121
buttonHref: string;
22+
tagColor?: string;
2223
}
2324

2425
export default function ProductCard({
@@ -30,6 +31,7 @@ export default function ProductCard({
3031
features,
3132
buttonLabel,
3233
buttonHref,
34+
tagColor = "bg-emerald-100 text-emerald-700",
3335
}: ProductCardProps) {
3436
return (
3537
<Card className="flex flex-col h-full shadow-md">
@@ -42,7 +44,7 @@ export default function ProductCard({
4244
</div>
4345
<Badge
4446
variant="secondary"
45-
className="bg-emerald-100 text-emerald-700"
47+
className={tagColor}
4648
>
4749
{launchDate}
4850
</Badge>

src/components/interactive/ReportCard.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button";
88
import { Check, X, Download, Shield, LogIn } from "lucide-react";
99
import { EXTERNAL } from '@/constant';
1010
import { getUserProfile, getLoginUrl, type UserProfile } from '@/lib/utils';
11+
import { Checkbox } from "@/components/ui/checkbox";
1112
import LoginMask from './LoginMask';
1213
import PrintableReport from './PrintableReport';
1314

@@ -29,6 +30,7 @@ type Report = {
2930
candidate_advice: string;
3031
concern_tags: string[];
3132
date_created: string;
33+
opt_in_talent_pool?: boolean;
3234
submission?: {
3335
job_description?: {
3436
id: string;
@@ -64,6 +66,8 @@ export default function ReportCard() {
6466
const [reportId, setReportId] = useState<string | null>(null);
6567
const [currentUser, setCurrentUser] = useState<UserProfile | null>(null);
6668
const [authChecked, setAuthChecked] = useState(false);
69+
const [talentPoolOptIn, setTalentPoolOptIn] = useState(false);
70+
const [talentPoolSubmitting, setTalentPoolSubmitting] = useState(false);
6771
const printRef = useRef<HTMLDivElement>(null);
6872

6973
const blacklist = ["Bounteer Production", ""];
@@ -73,6 +77,37 @@ export default function ReportCard() {
7377
documentTitle: `Role-Fit-Report-${reportId || 'unknown'}`,
7478
});
7579

80+
const handleTalentPoolOptIn = async () => {
81+
if (!report || !currentUser) return;
82+
83+
setTalentPoolSubmitting(true);
84+
try {
85+
const response = await fetch(`${EXTERNAL.directus_url}/items/role_fit_index_report/${report.id}`, {
86+
method: 'PATCH',
87+
headers: {
88+
'Content-Type': 'application/json',
89+
'Authorization': `Bearer ${EXTERNAL.directus_key}`
90+
},
91+
body: JSON.stringify({
92+
opt_in_talent_pool: talentPoolOptIn
93+
})
94+
});
95+
96+
if (!response.ok) {
97+
throw new Error('Failed to update talent pool preference');
98+
}
99+
100+
// Show success message
101+
alert(talentPoolOptIn ? 'Successfully opted in to Bounteer Talent Pool!' : 'Successfully opted out of Bounteer Talent Pool.');
102+
103+
} catch (error) {
104+
console.error('Error updating talent pool preference:', error);
105+
alert('Failed to update talent pool preference. Please try again.');
106+
} finally {
107+
setTalentPoolSubmitting(false);
108+
}
109+
};
110+
76111
const downloadCV = async (fileId: string) => {
77112
try {
78113
// First get file info to get the filename
@@ -182,6 +217,11 @@ export default function ReportCard() {
182217
}
183218

184219
setReport(reportData);
220+
221+
// Set talent pool opt-in state from report data
222+
if (reportData?.opt_in_talent_pool !== undefined) {
223+
setTalentPoolOptIn(reportData.opt_in_talent_pool);
224+
}
185225
} catch (e: any) {
186226
setError(e.message || "Unexpected error");
187227
} finally {
@@ -511,6 +551,46 @@ export default function ReportCard() {
511551
</div>
512552
</div>
513553

554+
{/* Talent Pool Opt-in - Only show if role fit index > 75 and user is authenticated */}
555+
{report.index > 75 && currentUser && (
556+
<div className="border-t pt-6">
557+
<h2 className="text-lg font-semibold mb-3">🎯 Join Bounteer Talent Pool</h2>
558+
<div className="rounded-lg bg-green-50 border border-green-200 p-5">
559+
<div className="flex items-start space-x-3">
560+
<Checkbox
561+
id="talentPoolOptIn"
562+
checked={talentPoolOptIn}
563+
onCheckedChange={setTalentPoolOptIn}
564+
className="mt-1"
565+
/>
566+
<div className="flex-1">
567+
<label
568+
htmlFor="talentPoolOptIn"
569+
className="font-medium text-green-900 cursor-pointer"
570+
>
571+
Get matched with relevant job opportunities
572+
</label>
573+
<p className="text-sm text-green-700 mt-1">
574+
With a {report.index}/100 Role Fit Index, you're a great candidate!
575+
Join our talent pool to get matched with hiring partners looking for candidates like you.
576+
Your profile and report data will only be shared when there's a strong match.
577+
</p>
578+
</div>
579+
</div>
580+
<div className="mt-4 flex justify-end">
581+
<Button
582+
onClick={handleTalentPoolOptIn}
583+
disabled={talentPoolSubmitting}
584+
variant="default"
585+
size="sm"
586+
>
587+
{talentPoolSubmitting ? "Saving..." : "Save Preference"}
588+
</Button>
589+
</div>
590+
</div>
591+
</div>
592+
)}
593+
514594
{/* Download Button */}
515595
<div className="flex justify-center pt-4">
516596
<Button

src/components/interactive/UserReportTable.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "@/components/ui/table";
1313
import { Input } from "@/components/ui/input";
1414
import { Button } from "@/components/ui/button";
15+
import { Badge } from "@/components/ui/badge";
1516
import { ExternalLink } from "lucide-react";
1617
import { EXTERNAL } from "@/constant";
1718
import { getUserProfile, type UserProfile } from "@/lib/utils";
@@ -26,6 +27,7 @@ type ReportRow = {
2627
index: number;
2728
weighted_index?: number;
2829
date_created: string;
30+
opt_in_talent_pool?: boolean;
2931
submission?: {
3032
id: number;
3133
cv_file?: string; // Directus file UUID
@@ -198,6 +200,7 @@ export default function UserReportTable({ pageSize = 10 }: Props) {
198200
<TableHead className="w-18">RFI</TableHead>
199201
<TableHead className="w-18">WRFI</TableHead>
200202
<TableHead>Job Description (JD)</TableHead>
203+
<TableHead className="w-32">Talent Pool</TableHead>
201204
<TableHead className="w-32">JD Link</TableHead>
202205
<TableHead className="w-32">CV Link</TableHead>
203206
</TableRow>
@@ -206,7 +209,7 @@ export default function UserReportTable({ pageSize = 10 }: Props) {
206209
{pageSlice.length === 0 ? (
207210
<TableRow>
208211
<TableCell
209-
colSpan={6}
212+
colSpan={7}
210213
className="text-center py-8 text-gray-500"
211214
>
212215
No reports found.
@@ -234,6 +237,23 @@ export default function UserReportTable({ pageSize = 10 }: Props) {
234237
<TableCell >{r.index}</TableCell>
235238
<TableCell >{r.weighted_index || "—"}</TableCell>
236239
<TableCell>{jobName}</TableCell>
240+
<TableCell>
241+
{r.index > 75 ? (
242+
r.opt_in_talent_pool ? (
243+
<Badge variant="default" className="bg-green-100 text-green-800 hover:bg-green-200">
244+
✓ Opted In
245+
</Badge>
246+
) : (
247+
<Badge variant="secondary" className="bg-gray-100 text-gray-600">
248+
Not Opted In
249+
</Badge>
250+
)
251+
) : (
252+
<Badge variant="outline" className="text-gray-400 border-gray-300">
253+
Not Eligible
254+
</Badge>
255+
)}
256+
</TableCell>
237257
<TableCell >
238258
<Button
239259
asChild

src/components/ui/checkbox.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import { cn } from "@/lib/utils"
5+
6+
export interface CheckboxProps
7+
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
8+
onCheckedChange?: (checked: boolean) => void;
9+
}
10+
11+
const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
12+
({ className, onCheckedChange, ...props }, ref) => {
13+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
14+
if (onCheckedChange) {
15+
onCheckedChange(e.target.checked);
16+
}
17+
};
18+
19+
return (
20+
<input
21+
type="checkbox"
22+
className={cn(
23+
"h-4 w-4 rounded border border-gray-300 text-primary-600 focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 focus:border-primary-600",
24+
className
25+
)}
26+
onChange={handleChange}
27+
ref={ref}
28+
{...props}
29+
/>
30+
)
31+
}
32+
)
33+
Checkbox.displayName = "Checkbox"
34+
35+
export { Checkbox }

src/pages/role-fit-index/index.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import RoleFitForm from "@/components/interactive/RoleFitIndexForm";
1111

1212
<main>
1313
<HeroSection
14-
title="Get Your Role Fit Index"
14+
title="Get Your Bounteer Role Fit Index"
1515
highlightText="Role Fit Index"
16-
description="Instantly analyze how well your CV matches a job description and learn how to improve your CV."
16+
description="Bounteer Role Fit Index (RFI) doesn’t just tell you how well you match a job. It shows you exactly what to do next. Get a clear match score, pinpoint your missing skills, and receive concrete upgrade tips to make your CV stand out. See how recruiters might view you, fix weak spots instantly, and boost your chances of landing interviews."
1717
badge="⚡ AI-Powered Career Matching"
1818
/>
1919

0 commit comments

Comments
 (0)