11'use client'
22import { JobApplication } from '@/db/types'
33import { Button } from '../../ui/button'
4- import { useRouter } from '@bprogress/next/app'
5- import { ExternalLink , Loader2 } from 'lucide-react'
6- import { useMemo , useState } from 'react'
4+ import { Loader2 } from 'lucide-react'
5+ import { useState } from 'react'
76import {
87 AlertDialog ,
98 AlertDialogContent ,
@@ -19,10 +18,10 @@ import { Input } from '../../ui/input'
1918import { useSearch } from '@/hooks/use-search'
2019import { JobApplicationsTableSkeleton } from './job-applications-table-skeleton'
2120import { DataTable } from '../../ui/data-table'
22- import { ColumnDef } from '@tanstack/react-table'
23- import { Badge } from '../../ui/badge'
2421import { cn } from '@/lib/utils'
25- import { Checkbox } from '@/components/ui/checkbox'
22+ import { useJobApplicationsTableColumns } from './use-job-applications-table-columns'
23+ import { Table } from '@tanstack/react-table'
24+
2625interface Props {
2726 jobApplications : JobApplication [ ]
2827 className ?: string
@@ -46,121 +45,51 @@ export const JobApplicationsTable = ({
4645 } )
4746 const [ containerHeight , setContainerHeight ] = useState < number > ( 600 )
4847
49- const router = useRouter ( )
5048 const { mutateAsync : removeJobApplications , isPending : isRemoving } =
5149 useRemoveJobApplications ( )
5250
5351 const [ removingIds , setRemovingIds ] = useState < string [ ] > ( [ ] )
5452
55- const columns : ColumnDef < JobApplication > [ ] = useMemo ( ( ) => {
56- const selectColumn : ColumnDef < JobApplication > = {
57- id : 'select' ,
58- header : ( { table } ) => (
59- < Checkbox
60- checked = {
61- table . getIsAllPageRowsSelected ( ) ||
62- ( table . getIsSomePageRowsSelected ( ) && 'indeterminate' )
63- }
64- onCheckedChange = { ( value ) => table . toggleAllPageRowsSelected ( ! ! value ) }
65- />
66- ) ,
67- cell : ( { row } ) => (
68- < Checkbox
69- checked = { row . getIsSelected ( ) }
70- onCheckedChange = { ( value ) => row . toggleSelected ( ! ! value ) }
71- />
72- ) ,
73- enableSorting : false ,
74- enableHiding : false ,
75- footer : footer
76- ? ( { table } ) => (
77- < div >
78- Selected { table . getFilteredSelectedRowModel ( ) . rows . length } of{ ' ' }
79- { jobApplications . length } applications
80- </ div >
81- )
82- : undefined ,
83- }
84-
85- const columns_ : ColumnDef < JobApplication > [ ] = [
86- {
87- header : 'Company' ,
88- cell : ( { row } ) => (
89- < div className = "truncate w-40" >
90- { row . original . companyName ?? 'N/A' }
91- </ div >
92- ) ,
93- } ,
94- {
95- header : 'Job Title' ,
96- cell : ( { row } ) => (
97- < div className = "truncate w-60" > { row . original . jobTitle ?? 'N/A' } </ div >
98- ) ,
99- } ,
100- {
101- header : 'Job Description' ,
102- cell : ( { row } ) => (
103- < div className = "truncate w-[500px]" >
104- { row . original . jobDescription }
105- </ div >
106- ) ,
107- id : 'jobDescription' ,
108- } ,
109- {
110- accessorFn : ( row ) =>
111- new Intl . DateTimeFormat ( 'en-US' ) . format (
112- new Date ( row . createdAt . toMillis ( ) ) ,
113- ) ,
114- header : 'Created At' ,
115- } ,
116- {
117- cell : ( { row } ) => {
118- const status = ( ( ) => {
119- if ( ! row . original . status ) {
120- return row . original . resume ? 'Completed' : 'Pending'
121- }
122- return (
123- row . original . status . slice ( 0 , 1 ) . toUpperCase ( ) +
124- row . original . status . slice ( 1 )
125- )
126- } ) ( )
127- return (
128- < Badge variant = { status === 'Completed' ? 'default' : 'secondary' } >
129- { status }
130- </ Badge >
131- )
132- } ,
133- header : 'Status' ,
134- } ,
135- {
136- id : 'actions' ,
137- cell : ( { row } ) => {
138- const jobApplication = row . original
139- return (
140- < div className = "text-right" >
141- < Button
142- onClick = { ( e ) => {
143- e . preventDefault ( )
144- e . stopPropagation ( )
145-
146- router . push ( `/adjust/${ jobApplication . id } ` )
147- } }
148- variant = "outline"
149- >
150- < ExternalLink />
151- </ Button >
152- </ div >
153- )
154- } ,
155- } ,
156- ]
53+ const columns = useJobApplicationsTableColumns ( {
54+ jobApplications,
55+ footer,
56+ selectable,
57+ } )
15758
158- if ( selectable ) {
159- return [ selectColumn , ...columns_ ]
59+ const renderHeader = ( { table } : { table : Table < JobApplication > } ) => {
60+ if ( ! search ) {
61+ return null
16062 }
16163
162- return columns_
163- } , [ footer , jobApplications . length , router , selectable ] )
64+ const selectedRows = table . getFilteredSelectedRowModel ( ) . rows
65+ return (
66+ < div className = "flex items-center justify-between gap-2 h-16" >
67+ < Input
68+ className = "w-96 max-w-full"
69+ value = { searchQuery }
70+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
71+ placeholder = "Search by job title, company name, or description..."
72+ />
73+ < Button
74+ className = { cn (
75+ selectedRows . length === 0 ? 'opacity-0!' : 'opacity-100' ,
76+ 'transition-opacity duration-300' ,
77+ ) }
78+ variant = "destructive"
79+ disabled = { selectedRows . length === 0 }
80+ onClick = { ( ) => {
81+ setRemovingIds (
82+ selectedRows
83+ . map ( ( row ) => row . original . id )
84+ . filter ( ( id ) => id !== undefined ) ,
85+ )
86+ } }
87+ >
88+ Delete
89+ </ Button >
90+ </ div >
91+ )
92+ }
16493
16594 if ( loading ) {
16695 return < JobApplicationsTableSkeleton />
@@ -180,36 +109,7 @@ export const JobApplicationsTable = ({
180109 columns = { columns }
181110 data = { searchResults }
182111 height = { containerHeight }
183- header = { ( { table } ) => {
184- const selectedRows = table . getFilteredSelectedRowModel ( ) . rows
185- return search ? (
186- < div className = "flex items-center justify-between gap-2 h-16" >
187- < Input
188- className = "w-96 max-w-full"
189- value = { searchQuery }
190- onChange = { ( e ) => setSearchQuery ( e . target . value ) }
191- placeholder = "Search by job title, company name, or description..."
192- />
193- < Button
194- className = { cn (
195- selectedRows . length === 0 ? 'opacity-0!' : 'opacity-100' ,
196- 'transition-opacity duration-300' ,
197- ) }
198- variant = "destructive"
199- disabled = { selectedRows . length === 0 }
200- onClick = { ( ) => {
201- setRemovingIds (
202- selectedRows
203- . map ( ( row ) => row . original . id )
204- . filter ( ( id ) => id !== undefined ) ,
205- )
206- } }
207- >
208- Delete
209- </ Button >
210- </ div >
211- ) : null
212- } }
112+ header = { renderHeader }
213113 />
214114
215115 < AlertDialog
0 commit comments