11import React , { useState } from 'react' ;
22import { Link , useNavigate } from 'react-router-dom' ;
3- import { MagnifyingGlass , Funnel , CaretUp , CaretDown , Check } from '@phosphor-icons/react' ;
4- import { getStatusClasses , getPriorityClasses , statusTextColor } from '../../utils/roadmapHelpers' ;
3+ import { MagnifyingGlass , Funnel , CaretUp , CaretDown , Check , Lightning , ArrowsDownUp } from '@phosphor-icons/react' ;
4+ import { getStatusClasses , getPriorityClasses } from '../../utils/roadmapHelpers' ;
55
66const TableView = ( { issuesData = [ ] } ) => {
77 const navigate = useNavigate ( ) ;
@@ -21,7 +21,8 @@ const TableView = ({ issuesData = [] }) => {
2121 const filteredApps = issuesData . filter ( ( app ) => {
2222 const matchesFilter = activeFilters . length === 0 || activeFilters . includes ( app . status || 'Planned' ) ;
2323 const matchesSearch = ( app . title ?. toLowerCase ( ) || '' ) . includes ( searchQuery . toLowerCase ( ) ) ||
24- ( app . description ?. toLowerCase ( ) || '' ) . includes ( searchQuery . toLowerCase ( ) ) ;
24+ ( app . description ?. toLowerCase ( ) || '' ) . includes ( searchQuery . toLowerCase ( ) ) ||
25+ ( app . epic ?. toLowerCase ( ) || '' ) . includes ( searchQuery . toLowerCase ( ) ) ;
2526 return matchesFilter && matchesSearch ;
2627 } ) ;
2728
@@ -41,6 +42,8 @@ const TableView = ({ issuesData = [] }) => {
4142 comparison =
4243 priorityOrder . indexOf ( a . priority || 'Low' ) -
4344 priorityOrder . indexOf ( b . priority || 'Low' ) ;
45+ } else if ( sortBy === 'epic' ) {
46+ comparison = ( a . epic || '' ) . localeCompare ( b . epic || '' ) ;
4447 }
4548
4649 return sortOrder === 'asc' ? comparison : - comparison ;
@@ -56,8 +59,10 @@ const TableView = ({ issuesData = [] }) => {
5659 } ;
5760
5861 const SortIcon = ( { column } ) => {
59- if ( sortBy !== column ) return < div className = "w-4 h-4" /> ; // Placeholder to prevent layout shift
60- return sortOrder === 'asc' ? < CaretUp weight = "bold" size = { 14 } /> : < CaretDown weight = "bold" size = { 14 } /> ;
62+ if ( sortBy !== column ) {
63+ return < ArrowsDownUp size = { 14 } weight = "bold" className = "text-gray-500 opacity-70 group-hover:opacity-100 group-hover:text-primary-400 transition-all" /> ;
64+ }
65+ return sortOrder === 'asc' ? < CaretUp weight = "bold" size = { 14 } className = "text-primary-400" /> : < CaretDown weight = "bold" size = { 14 } className = "text-primary-400" /> ;
6166 } ;
6267
6368 return (
@@ -71,7 +76,7 @@ const TableView = ({ issuesData = [] }) => {
7176 </ div >
7277 < input
7378 type = "text"
74- placeholder = "Search issues by title or description ..."
79+ placeholder = "Search issues by title, description, or epic ..."
7580 value = { searchQuery }
7681 onChange = { ( e ) => setSearchQuery ( e . target . value ) }
7782 className = "block w-full pl-11 pr-4 py-3 border border-gray-700 rounded-xl leading-5 bg-gray-800/50 text-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500/50 focus:border-primary-500 focus:bg-gray-800 transition-all duration-300 text-sm font-mono"
@@ -89,10 +94,10 @@ const TableView = ({ issuesData = [] }) => {
8994 key = { status }
9095 onClick = { ( ) => handleFilterChange ( status ) }
9196 className = { `
92- group relative px-3 py-1.5 rounded-lg text-xs font-mono font-bold transition-all duration-200 border select-none
97+ group relative px-3 py-1.5 rounded-lg text-xs font-mono font-bold uppercase tracking-wider transition-all duration-200 select-none
9398 ${ activeFilters . includes ( status )
94- ? `${ getStatusClasses ( status ) . split ( ' ' ) [ 0 ] } ${ getStatusClasses ( status ) . split ( ' ' ) [ 1 ] } ${ statusTextColor ( status ) } shadow-md ring-1 ring-white/10`
95- : 'bg-gray-800/40 border-gray-700 text-gray-500 hover:border-gray-600 hover:bg-gray-800 hover:text-gray-300'
99+ ? `${ getStatusClasses ( status ) } shadow-md ring-1 ring-white/10`
100+ : 'bg-gray-800/40 border border -gray-700 text-gray-500 hover:border-gray-600 hover:bg-gray-800 hover:text-gray-300'
96101 }
97102 ` }
98103 >
@@ -114,6 +119,7 @@ const TableView = ({ issuesData = [] }) => {
114119 < tr className = "bg-gray-800/60" >
115120 { [
116121 { key : 'title' , label : 'Title' } ,
122+ { key : 'epic' , label : 'Epic' } ,
117123 { key : 'description' , label : 'Description' , noSort : true } ,
118124 { key : 'status' , label : 'Status' } ,
119125 { key : 'priority' , label : 'Priority' } ,
@@ -125,7 +131,7 @@ const TableView = ({ issuesData = [] }) => {
125131 scope = "col"
126132 onClick = { ( ) => ! col . noSort && handleSort ( col . key ) }
127133 className = { `
128- px-6 py-4 text-left text-xs font-mono font-bold text-gray-400 uppercase tracking-wider
134+ px-6 py-4 text-left text-xs font-mono font-bold text-gray-400 uppercase tracking-wider group
129135 ${ ! col . noSort ? 'cursor-pointer hover:text-primary-400 hover:bg-gray-800/50 transition-colors select-none' : '' }
130136 ` }
131137 >
@@ -159,21 +165,26 @@ const TableView = ({ issuesData = [] }) => {
159165 { app . title }
160166 </ Link >
161167 </ td >
168+ < td className = "px-6 py-4 whitespace-nowrap" >
169+ { app . epic ? (
170+ < span className = "inline-flex items-center gap-1.5 px-2 py-1 rounded bg-purple-500/10 border border-purple-500/30 text-purple-300 text-[10px] font-mono uppercase tracking-wider font-bold" >
171+ < Lightning weight = "fill" size = { 10 } />
172+ { app . epic }
173+ </ span >
174+ ) : (
175+ < span className = "text-gray-600 font-mono text-xs" > -</ span >
176+ ) }
177+ </ td >
162178 < td className = "px-6 py-4 text-sm text-gray-400 font-mono max-w-xs truncate" title = { app . description } >
163179 { app . description }
164180 </ td >
165181 < td className = "px-6 py-4 whitespace-nowrap" >
166- < span className = { `px-2.5 py-1 inline-flex items-center text-[10px] font-mono font-bold uppercase tracking-wide rounded-full border ${ getStatusClasses ( app . status ) } ${ statusTextColor ( app . status ) } shadow-sm` } >
182+ < span className = { `px-2.5 py-1 inline-flex items-center text-[10px] font-mono font-bold uppercase tracking-wide rounded-full ${ getStatusClasses ( app . status ) } shadow-sm` } >
167183 { app . status || 'Planned' }
168184 </ span >
169185 </ td >
170186 < td className = "px-6 py-4 whitespace-nowrap" >
171- < span className = { `flex items-center gap-2 text-xs font-mono font-bold ${ getPriorityClasses ( app . priority ) . split ( ' ' ) [ 0 ] } ` } >
172- < span className = { `w-2 h-2 rounded-full ${
173- app . priority === 'High' ? 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.6)]' :
174- app . priority === 'Medium' ? 'bg-yellow-500 shadow-[0_0_8px_rgba(234,179,8,0.6)]' :
175- 'bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]'
176- } `} > </ span >
187+ < span className = { `inline-flex items-center gap-1.5 px-2 py-1 rounded text-[10px] font-mono font-bold uppercase tracking-wide ${ getPriorityClasses ( app . priority ) } ` } >
177188 { app . priority || 'Low' }
178189 </ span >
179190 </ td >
@@ -187,7 +198,7 @@ const TableView = ({ issuesData = [] }) => {
187198 ) )
188199 ) : (
189200 < tr >
190- < td colSpan = "6 " className = "px-6 py-16 text-center text-gray-500 font-mono" >
201+ < td colSpan = "7 " className = "px-6 py-16 text-center text-gray-500 font-mono" >
191202 < div className = "flex flex-col items-center justify-center gap-4" >
192203 < div className = "p-4 rounded-full bg-gray-800/50" >
193204 < MagnifyingGlass size = { 32 } className = "opacity-50" />
0 commit comments