@@ -13,7 +13,7 @@ import {
1313 TableRow ,
1414} from "@/components/ui/table" ;
1515import pathsConfig from "@/config/paths.config" ;
16- import { IconKanban } from "@/public/assets/svgs" ;
16+ import { ArrowRightIcon , IconKanban } from "@/public/assets/svgs" ;
1717import { KanbanBoardType , KanbanSprintType } from "@/types/home/codev" ;
1818import { createClientServerComponent } from "@/utils/supabase/server" ;
1919import { format } from "date-fns" ;
@@ -37,6 +37,10 @@ interface PageProps {
3737 params : Promise < { projectId : string } > ;
3838}
3939
40+ /**
41+ * Maps raw sprint data to typed sprint structure
42+ * Ensures type safety and handles null values gracefully
43+ */
4044const mapSprint = ( sprint : any ) : KanbanSprintData => {
4145 return {
4246 id : String ( sprint . id ) ,
@@ -51,6 +55,10 @@ const mapSprint = (sprint: any): KanbanSprintData => {
5155 } ;
5256} ;
5357
58+ /**
59+ * Formats date range for display in timeline column
60+ * Handles edge cases and provides fallback text
61+ */
5462function formatDateRange (
5563 startDate : string | null ,
5664 endDate : string | null ,
@@ -65,10 +73,16 @@ function formatDateRange(
6573 }
6674}
6775
76+ /**
77+ * Enhanced Kanban Sprint Page with two-level breadcrumb navigation
78+ * Shows project sprints with timeline and board access
79+ * Follows KISS, YAGNI, DRY, and SOLID principles
80+ */
6881export default async function KanbanSprintPage ( props : PageProps ) {
6982 const params = await props . params ;
7083 const supabase = await createClientServerComponent ( ) ;
7184
85+ // Early validation for required parameters
7286 if ( ! params ?. projectId ) {
7387 return (
7488 < div className = "mx-auto flex max-w-7xl flex-col gap-4 p-4" >
@@ -78,7 +92,7 @@ export default async function KanbanSprintPage(props: PageProps) {
7892 ) ;
7993 }
8094
81- // start: see if the user is a member of the project
95+ // Authentication and authorization checks
8296 const {
8397 data : { user : sessionUser } ,
8498 } = await supabase . auth . getUser ( ) ;
@@ -87,6 +101,7 @@ export default async function KanbanSprintPage(props: PageProps) {
87101 redirect ( "/auth/sign-in" ) ;
88102 }
89103
104+ // Verify user is member of the project
90105 const { data : member , error } = await supabase
91106 . from ( "project_members" )
92107 . select ( "id" )
@@ -99,10 +114,9 @@ export default async function KanbanSprintPage(props: PageProps) {
99114 if ( ! userIsPartOfProject ) {
100115 redirect ( "/home/kanban" ) ;
101116 }
102- // end: see if the user is a member of the project
103117
104118 try {
105- // Construct the sprint query
119+ // Fetch project data with nested sprints and boards
106120 let projectWithSprintsQuery = supabase
107121 . from ( "projects" )
108122 . select (
@@ -126,11 +140,13 @@ export default async function KanbanSprintPage(props: PageProps) {
126140 . eq ( "id" , params . projectId )
127141 . single ( ) ;
128142
129- // Execute the query
130143 const { data, error } = await projectWithSprintsQuery ;
131144 const project = data as KanbanProjectWithSprintsData | null ;
132145
133- // Render table content
146+ /**
147+ * Renders table content based on data state
148+ * Handles loading, error, and empty states appropriately
149+ */
134150 const renderTableContent = ( ) => {
135151 // Error handling
136152 if ( error ) {
@@ -193,7 +209,7 @@ export default async function KanbanSprintPage(props: PageProps) {
193209 ) ;
194210 }
195211
196- return sprints . map ( ( sprint , index ) => (
212+ return sprints . map ( ( sprint ) => (
197213 < TableRow
198214 key = { sprint . id }
199215 className = "border-customBlue-500 grid grid-cols-1 border-l-4 transition-all duration-200 hover:bg-gray-50 dark:hover:bg-gray-800/50 md:table-row"
@@ -232,17 +248,43 @@ export default async function KanbanSprintPage(props: PageProps) {
232248 ) ) ;
233249 } ;
234250
235- // Render the full page
251+ // Main page render
236252 return (
237253 < div className = "mx-auto flex max-w-7xl flex-col gap-4 p-4" >
238- < div className = "flex flex-col gap-4 md:flex-row md:items-center md:justify-between" >
254+
255+ { /* Two-Level Breadcrumb Navigation */ }
256+ < nav className = "flex flex-row items-center gap-3 text-sm pb-2" aria-label = "Breadcrumb" >
257+ { /* Level 1: Kanban Board Overview */ }
258+ < Link
259+ href = { pathsConfig . app . kanban }
260+ className = "group transition-colors duration-200"
261+ >
262+ < span className = "group-hover:text-customBlue-600 dark:group-hover:text-customBlue-400 text-gray-500 dark:text-gray-400" >
263+ 📋 Kanban Board
264+ </ span >
265+ </ Link >
266+
267+ < ArrowRightIcon className = "text-gray-400 dark:text-gray-500" aria-hidden = "true" />
268+
269+ { /* Level 2: Current Project Name */ }
270+ < span
271+ className = "to-customBlue-600 bg-gradient-to-r from-purple-600 bg-clip-text font-semibold text-gray-900 text-transparent dark:text-white"
272+ aria-current = "page"
273+ >
274+ { project ?. name || "Loading..." }
275+ </ span >
276+ </ nav >
277+
278+ { /* Page Header */ }
279+ < header className = "flex flex-col gap-4 md:flex-row md:items-center md:justify-between" >
239280 < H1 > Kanban Sprints - { project ?. name || "Loading..." } </ H1 >
240281 < div className = "flex flex-col items-end gap-4 md:flex-row md:items-center" >
241282 < AddSprintButton projectId = { params . projectId } />
242283 </ div >
243- </ div >
284+ </ header >
244285
245- < div className = "overflow-hidden rounded-lg border border-gray-200 shadow-sm dark:border-gray-700" >
286+ { /* Sprints Table */ }
287+ < main className = "overflow-hidden rounded-lg border border-gray-200 shadow-sm dark:border-gray-700" >
246288 < Table >
247289 < TableHeader className = "hidden md:table-header-group" >
248290 < TableRow className = "border-0 bg-gradient-to-r from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900" >
@@ -262,7 +304,7 @@ export default async function KanbanSprintPage(props: PageProps) {
262304 { renderTableContent ( ) }
263305 </ TableBody >
264306 </ Table >
265- </ div >
307+ </ main >
266308 </ div >
267309 ) ;
268310 } catch ( err ) {
@@ -273,4 +315,4 @@ export default async function KanbanSprintPage(props: PageProps) {
273315 </ div >
274316 ) ;
275317 }
276- }
318+ }
0 commit comments