66 useReactTable ,
77} from '@tanstack/react-table' ;
88import classNames from 'classnames' ;
9+ import { format } from 'date-fns' ;
910import {
1011 Typography ,
1112 TypographyColor ,
@@ -15,26 +16,10 @@ import {
1516import { getLastActivityDateFormat } from '../../lib/dateFormat' ;
1617import { MiniCloseIcon } from '../icons' ;
1718import { 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
3924const 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-
154159const 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"
0 commit comments