Skip to content

Commit f8309d7

Browse files
authored
feat: opportunity preview endpoint (#5126)
1 parent b484708 commit f8309d7

7 files changed

Lines changed: 287 additions & 125 deletions

File tree

packages/shared/src/components/recruiter/AnonymousUserTable.tsx

Lines changed: 62 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
useReactTable,
77
} from '@tanstack/react-table';
88
import classNames from 'classnames';
9+
import { format } from 'date-fns';
910
import {
1011
Typography,
1112
TypographyColor,
@@ -15,26 +16,10 @@ import {
1516
import { getLastActivityDateFormat } from '../../lib/dateFormat';
1617
import { MiniCloseIcon } from '../icons';
1718
import { Chip } from '../cards/common/PostTags';
19+
import { useOpportunityPreviewContext } from '../../contexts/OpportunityPreviewContext';
20+
import type { OpportunityPreviewUser } from '../../graphql/opportunities';
1821

19-
export type AnonymousUser = {
20-
id: string;
21-
profileImage: string;
22-
anonId: string;
23-
description: string;
24-
openToWork: boolean;
25-
seniority: string;
26-
location: string;
27-
company: {
28-
name: string;
29-
favicon?: string;
30-
};
31-
lastActivity: Date;
32-
topTags?: string[];
33-
recentlyRead?: string[];
34-
activeSquads?: string[];
35-
};
36-
37-
const columnHelper = createColumnHelper<AnonymousUser>();
22+
const columnHelper = createColumnHelper<OpportunityPreviewUser>();
3823

3924
const columns = [
4025
columnHelper.display({
@@ -44,11 +29,13 @@ const columns = [
4429
const user = info.row.original;
4530
return (
4631
<div className="relative size-10 flex-shrink-0 overflow-hidden rounded-12">
47-
<img
48-
src={user.profileImage}
49-
alt={user.anonId}
50-
className="size-full object-cover blur-sm"
51-
/>
32+
{user.profileImage && (
33+
<img
34+
src={user.profileImage}
35+
alt={user.anonId}
36+
className="size-full object-cover blur-sm"
37+
/>
38+
)}
5239
</div>
5340
);
5441
},
@@ -83,7 +70,7 @@ const columns = [
8370
type={TypographyType.Footnote}
8471
color={TypographyColor.Tertiary}
8572
>
86-
{info.getValue()}
73+
{info.getValue() || '-'}
8774
</Typography>
8875
),
8976
}),
@@ -94,14 +81,24 @@ const columns = [
9481
type={TypographyType.Footnote}
9582
color={TypographyColor.Tertiary}
9683
>
97-
{info.getValue()}
84+
{info.getValue() || '-'}
9885
</Typography>
9986
),
10087
}),
10188
columnHelper.accessor('company', {
10289
header: 'Company',
10390
cell: (info) => {
10491
const company = info.getValue();
92+
if (!company) {
93+
return (
94+
<Typography
95+
type={TypographyType.Footnote}
96+
color={TypographyColor.Tertiary}
97+
>
98+
-
99+
</Typography>
100+
);
101+
}
105102
return (
106103
<div className="flex items-center gap-2">
107104
{company.favicon && (
@@ -124,7 +121,19 @@ const columns = [
124121
columnHelper.accessor('lastActivity', {
125122
header: 'Last activity',
126123
cell: (info) => {
127-
const relativeTime = getLastActivityDateFormat(info.getValue());
124+
const value = info.getValue();
125+
if (!value) {
126+
return (
127+
<Typography
128+
type={TypographyType.Footnote}
129+
color={TypographyColor.Tertiary}
130+
>
131+
-
132+
</Typography>
133+
);
134+
}
135+
136+
const relativeTime = getLastActivityDateFormat(value);
128137
const isNow = relativeTime === 'Now';
129138

130139
if (isNow) {
@@ -147,10 +156,6 @@ const columns = [
147156
}),
148157
];
149158

150-
export type AnonymousUserTableProps = {
151-
data?: AnonymousUser[];
152-
};
153-
154159
const ChipSection = ({ label, items }: { label: string; items: string[] }) => {
155160
if (!items || items.length === 0) {
156161
return null;
@@ -177,9 +182,8 @@ const ChipSection = ({ label, items }: { label: string; items: string[] }) => {
177182
);
178183
};
179184

180-
export const AnonymousUserTable = ({
181-
data: propData,
182-
}: AnonymousUserTableProps) => {
185+
export const AnonymousUserTable = () => {
186+
const contextData = useOpportunityPreviewContext();
183187
const [showInfoBar, setShowInfoBar] = useState(true);
184188
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());
185189
const [hoveredRow, setHoveredRow] = useState<string | null>(null);
@@ -196,78 +200,16 @@ export const AnonymousUserTable = ({
196200
});
197201
};
198202

199-
const defaultData = useMemo<AnonymousUser[]>(
200-
() => [
201-
{
202-
id: '1',
203-
profileImage: 'https://i.pravatar.cc/150?img=1',
204-
anonId: 'Anon #1002',
205-
description:
206-
'A web developer with a strong focus on modern web technologies, performance optimization, and efficient development workflows. They are particularly interested in JavaScript/TypeScript runtimes (Bun), front-end frameworks (React, Vue.js, TanStack Start, Docusaurus, Astro), and UI component libraries (Reka UI), prioritizing accessibility and customization. Their curiosity extends to alternative programming languages like SmallJS and the critical analysis of web architecture, including HTML and the DOM. On the backend, they follow Node.js application servers (Watt 3) and are interested in Rust-based runtimes.',
207-
openToWork: true,
208-
seniority: 'Senior',
209-
location: 'San Francisco, CA',
210-
company: {
211-
name: 'TechCorp',
212-
favicon: 'https://www.google.com/s2/favicons?domain=techcrunch.com',
213-
},
214-
lastActivity: new Date(),
215-
topTags: ['JavaScript', 'React', 'TypeScript', 'Node.js', 'Bun'],
216-
recentlyRead: [
217-
'Modern Web Development',
218-
'Performance Optimization',
219-
'Accessibility Best Practices',
220-
],
221-
activeSquads: ['Frontend Developers', 'TypeScript Community', 'React'],
222-
},
223-
{
224-
id: '2',
225-
profileImage: 'https://i.pravatar.cc/150?img=5',
226-
anonId: 'Anon #1045',
227-
description:
228-
'An experienced full-stack engineer passionate about building scalable applications and exploring cutting-edge technologies. They have deep expertise in cloud infrastructure, microservices architecture, and DevOps practices. Their interests span across backend systems (Go, Python, Rust), container orchestration (Kubernetes, Docker), and serverless architectures. They actively contribute to open-source projects and enjoy mentoring junior developers.',
229-
openToWork: true,
230-
seniority: 'Mid-level',
231-
location: 'New York, NY',
232-
company: {
233-
name: 'StartupXYZ',
234-
favicon: 'https://www.google.com/s2/favicons?domain=github.com',
235-
},
236-
lastActivity: new Date(Date.now() - 1000 * 60 * 45), // 45 minutes ago
237-
topTags: ['Go', 'Kubernetes', 'Python', 'AWS', 'Docker'],
238-
recentlyRead: [
239-
'Microservices Architecture',
240-
'Cloud Native Development',
241-
'DevOps',
242-
],
243-
activeSquads: ['Backend Engineering', 'Cloud Native', 'DevOps'],
244-
},
245-
{
246-
id: '3',
247-
profileImage: 'https://i.pravatar.cc/150?img=8',
248-
anonId: 'Anon #1078',
249-
description:
250-
'A creative frontend specialist with a keen eye for design and user experience. They excel at building beautiful, accessible, and performant user interfaces using modern frameworks and design systems. Their expertise includes advanced CSS techniques, animation libraries, and responsive design patterns. They are passionate about creating inclusive web experiences and staying current with the latest design trends and best practices.',
251-
openToWork: false,
252-
seniority: 'Senior',
253-
location: 'Austin, TX',
254-
company: {
255-
name: 'DesignHub',
256-
favicon: 'https://www.google.com/s2/favicons?domain=figma.com',
257-
},
258-
lastActivity: new Date(Date.now() - 1000 * 60 * 60 * 3), // 3 hours ago
259-
topTags: ['CSS', 'UI/UX', 'Figma', 'Animation', 'Accessibility'],
260-
recentlyRead: ['Design Systems', 'CSS Architecture', 'Web Animations'],
261-
activeSquads: ['UI/UX Designers', 'Frontend', 'Design Systems'],
262-
},
263-
],
264-
[],
265-
);
266-
267-
const data = propData ?? defaultData;
203+
// Extract users from context data
204+
const tableData = useMemo<OpportunityPreviewUser[]>(() => {
205+
if (!contextData?.edges) {
206+
return [];
207+
}
208+
return contextData.edges.map((edge) => edge.node);
209+
}, [contextData]);
268210

269211
const table = useReactTable({
270-
data,
212+
data: tableData,
271213
columns,
272214
getCoreRowModel: getCoreRowModel(),
273215
});
@@ -374,20 +316,28 @@ export const AnonymousUserTable = ({
374316
className="border-b border-border-subtlest-tertiary px-4 pb-3 pt-1"
375317
>
376318
<div className="flex flex-col gap-2">
377-
<Typography
378-
type={TypographyType.Footnote}
379-
color={TypographyColor.Tertiary}
380-
className={classNames(!isExpanded && 'line-clamp-1')}
381-
>
382-
{user.description}
383-
</Typography>
319+
{user.description && (
320+
<Typography
321+
type={TypographyType.Footnote}
322+
color={TypographyColor.Tertiary}
323+
className={classNames(!isExpanded && 'line-clamp-1')}
324+
>
325+
{user.description}
326+
</Typography>
327+
)}
384328

385329
{isExpanded && (
386330
<>
387331
<ChipSection label="Top tags" items={user.topTags} />
388332
<ChipSection
389333
label="Recently read"
390-
items={user.recentlyRead}
334+
items={user.recentlyRead?.map((badge) => {
335+
const formattedDate = format(
336+
new Date(badge.issuedAt),
337+
'MMM yyyy',
338+
);
339+
return `${badge.keyword.value} - ${formattedDate}`;
340+
})}
391341
/>
392342
<ChipSection
393343
label="Active squads"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createContextProvider } from '@kickass-coderz/react';
2+
import { useOpportunityPreview } from '../graphql/opportunities';
3+
4+
const [OpportunityPreviewProvider, useOpportunityPreviewContext] =
5+
createContextProvider(() => {
6+
const { data } = useOpportunityPreview();
7+
8+
return { ...data };
9+
});
10+
11+
export { OpportunityPreviewProvider, useOpportunityPreviewContext };

0 commit comments

Comments
 (0)