1- import React from 'react' ;
1+ import React , { useState } from 'react' ;
22import { useSession } from 'next-auth/react' ;
33import { Tooltip } from 'react-tooltip' ;
44import ActiveTasksByProject from './ActiveTasksByProject' ;
@@ -20,9 +20,11 @@ import LoadingIndicator from './shared/LoadingIndicator';
2020import QuickStats from './QuickStats/QuickStats' ;
2121import { useDashboardData } from '../hooks/useDashboardData' ;
2222import Layout from './layout/Layout' ;
23+ import ProjectPicker from './ProjectPicker' ;
2324
2425export default function Dashboard ( ) : JSX . Element {
2526 const { status } = useSession ( ) ;
27+ const [ selectedProjectIds , setSelectedProjectIds ] = useState < string [ ] > ( [ ] ) ;
2628 const {
2729 data,
2830 isLoading,
@@ -98,15 +100,26 @@ export default function Dashboard(): JSX.Element {
98100 < div className = "min-h-screen rounded-lg bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 text-white" >
99101 < div className = "container mx-auto p-6" >
100102 < header className = "mb-8" >
101- < h1 className = "text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500 mb-2" >
102- Todoist Dashboard
103- </ h1 >
104- < p className = "text-gray-400" >
105- < span >
106- < SiTodoist className = "inline text-red-500 ml-1 mr-2" />
107- </ span >
108- Your productivity at a glance
109- </ p >
103+ < div className = "flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-4" >
104+ < div >
105+ < h1 className = "text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500 mb-2" >
106+ Todoist Dashboard
107+ </ h1 >
108+ < p className = "text-gray-400" >
109+ < span >
110+ < SiTodoist className = "inline text-red-500 ml-1 mr-2" />
111+ </ span >
112+ Your productivity at a glance
113+ </ p >
114+ </ div >
115+ { data ?. projectData && (
116+ < ProjectPicker
117+ projects = { data . projectData }
118+ selectedProjectIds = { selectedProjectIds }
119+ onProjectSelect = { setSelectedProjectIds }
120+ />
121+ ) }
122+ </ div >
110123 </ header >
111124
112125 { /* Always show loading indicator */ }
@@ -121,9 +134,13 @@ export default function Dashboard(): JSX.Element {
121134
122135 { /* Quick Stats */ }
123136 < QuickStats
124- activeTasks = { data ?. activeTasks || [ ] }
125- projectCount = { data ?. projectData ?. length || 0 }
126- totalCompletedTasks = { data ?. totalCompletedTasks || 0 }
137+ activeTasks = { selectedProjectIds . length > 0
138+ ? data ?. activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
139+ : data ?. activeTasks || [ ] }
140+ projectCount = { selectedProjectIds . length || data ?. projectData ?. length || 0 }
141+ totalCompletedTasks = { selectedProjectIds . length > 0
142+ ? data ?. allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) ?. length || 0
143+ : data ?. totalCompletedTasks || 0 }
127144 karma = { data ?. karma || 0 }
128145 karmaTrend = { data ?. karmaTrend || 'none' }
129146 karmaRising = { data ?. karmaRising || false }
@@ -134,7 +151,15 @@ export default function Dashboard(): JSX.Element {
134151 { /* Insights Section */ }
135152 < div className = "lg:col-span-3" >
136153 < Insights
137- allData = { data }
154+ allData = { {
155+ ...data ,
156+ activeTasks : selectedProjectIds . length > 0
157+ ? data ?. activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
158+ : data ?. activeTasks || [ ] ,
159+ allCompletedTasks : selectedProjectIds . length > 0
160+ ? data ?. allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
161+ : data ?. allCompletedTasks || [ ]
162+ } }
138163 isLoading = { isLoading }
139164 fullyLoaded = { ! needsFullData }
140165 />
@@ -145,7 +170,14 @@ export default function Dashboard(): JSX.Element {
145170 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
146171 Recently Completed < span className = "text-white" > ✅</ span >
147172 </ h2 >
148- < RecentlyCompletedList allData = { data } />
173+ < RecentlyCompletedList
174+ allData = { {
175+ ...data ,
176+ allCompletedTasks : selectedProjectIds . length > 0
177+ ? data ?. allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
178+ : data ?. allCompletedTasks || [ ]
179+ } }
180+ />
149181 </ div >
150182
151183 { /* Neglected Tasks Section */ }
@@ -154,7 +186,12 @@ export default function Dashboard(): JSX.Element {
154186 Neglected Tasks
155187 < QuestionMark content = "Tasks that have been on your list the longest without being completed. Consider reviewing these tasks to either complete them, reschedule, or remove if no longer relevant." />
156188 </ h2 >
157- < NeglectedTasks activeTasks = { activeTasks } projectData = { projectData } />
189+ < NeglectedTasks
190+ activeTasks = { selectedProjectIds . length > 0
191+ ? activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
192+ : activeTasks || [ ] }
193+ projectData = { projectData }
194+ />
158195 </ div >
159196
160197 { /* Recurring Tasks Section */ }
@@ -170,34 +207,45 @@ export default function Dashboard(): JSX.Element {
170207 </ div >
171208 ) : (
172209 < RecurringTasksPreview
173- activeTasks = { activeTasks }
174- allCompletedTasks = { allCompletedTasks }
210+ activeTasks = { selectedProjectIds . length > 0
211+ ? activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
212+ : activeTasks || [ ] }
213+ allCompletedTasks = { selectedProjectIds . length > 0
214+ ? allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
215+ : allCompletedTasks || [ ] }
175216 />
176217 ) }
177218 </ div >
178219
179220 { /* Task Management Section */ }
180221 < div className = "lg:col-span-3 grid grid-cols-1 sm:grid-cols-2 gap-6" >
181222 < div
182- className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : ''
183- } `}
223+ className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` }
184224 >
185225 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
186226 Tasks by Priority
187227 </ h2 >
188- < TaskPriority activeTasks = { data ?. activeTasks || [ ] } loading = { needsFullData } />
228+ < TaskPriority
229+ activeTasks = { selectedProjectIds . length > 0
230+ ? data ?. activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
231+ : data ?. activeTasks || [ ] }
232+ loading = { needsFullData }
233+ />
189234 </ div >
190235
191236 < div
192- className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : ''
193- } `}
237+ className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` }
194238 >
195239 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
196240 Active Tasks by Project
197241 </ h2 >
198242 < ActiveTasksByProject
199- projectData = { data ?. projectData || [ ] }
200- activeTasks = { data ?. activeTasks || [ ] }
243+ projectData = { selectedProjectIds . length > 0
244+ ? projectData ?. filter ( project => selectedProjectIds . includes ( project . id ) ) || [ ]
245+ : projectData || [ ] }
246+ activeTasks = { selectedProjectIds . length > 0
247+ ? activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ]
248+ : activeTasks || [ ] }
201249 loading = { needsFullData }
202250 />
203251 </ div >
@@ -206,52 +254,77 @@ export default function Dashboard(): JSX.Element {
206254 { /* Completed Tasks over time and by project */ }
207255 < div className = "lg:col-span-3 grid grid-cols-1 sm:grid-cols-2 gap-6" >
208256 < div
209- className = { `bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : ''
210- } `}
257+ className = { `bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` }
211258 >
212259 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
213260 Completed Tasks Over Time
214261 </ h2 >
215- < CompletedTasksOverTime allData = { allCompletedTasks } loading = { isLoading } />
262+ < CompletedTasksOverTime
263+ allData = { selectedProjectIds . length > 0
264+ ? allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
265+ : allCompletedTasks || [ ] }
266+ loading = { isLoading }
267+ />
216268 </ div >
217269
218270 < div className = { `flex flex-col bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` } >
219271 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
220272 Completed Tasks by Project
221273 </ h2 >
222274 < CompletedTasksByProject
223- projectData = { projectData . map ( ( project ) => ( {
224- ...project ,
225- completedTasksCount : allCompletedTasks . filter (
226- ( task ) => task . project_id === project . id
227- ) . length ,
228- } ) ) }
275+ projectData = { selectedProjectIds . length > 0
276+ ? projectData
277+ . filter ( project => selectedProjectIds . includes ( project . id ) )
278+ . map ( project => ( {
279+ ...project ,
280+ completedTasksCount : allCompletedTasks . filter (
281+ task => task . project_id === project . id
282+ ) . length ,
283+ } ) ) || [ ]
284+ : projectData . map ( ( project ) => ( {
285+ ...project ,
286+ completedTasksCount : allCompletedTasks . filter (
287+ ( task ) => task . project_id === project . id
288+ ) . length ,
289+ } ) ) || [ ] }
229290 loading = { needsFullData }
230291 />
231292 </ div >
232293 </ div >
233294
234295 < div className = "lg:col-span-3 grid grid-cols-1 sm:grid-cols-2 gap-6" >
235296 < div
236- className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : ''
237- } `}
297+ className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` }
238298 >
239299 < div className = "flex items-center gap-2" >
240300 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
241301 Daily Streak
242302 </ h2 >
243303 </ div >
244- < CompletionStreak allData = { data } />
304+ < CompletionStreak
305+ allData = { {
306+ allCompletedTasks : selectedProjectIds . length > 0
307+ ? data ?. allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
308+ : data ?. allCompletedTasks || [ ]
309+ } }
310+ />
245311 </ div >
246312
247313 < div
248- className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : ''
249- } `}
314+ className = { `lg:col-span-1 bg-gray-800 rounded-xl p-4 sm:p-6 shadow-lg ${ needsFullData ? 'opacity-50' : '' } ` }
250315 >
251316 < h2 className = "text-lg sm:text-xl font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500" >
252317 Daily Activity Pattern
253318 </ h2 >
254- < CompletedByTimeOfDay allData = { data } loading = { needsFullData } />
319+ < CompletedByTimeOfDay
320+ allData = { {
321+ ...data ,
322+ allCompletedTasks : selectedProjectIds . length > 0
323+ ? data ?. allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ]
324+ : data ?. allCompletedTasks || [ ]
325+ } }
326+ loading = { needsFullData }
327+ />
255328 </ div >
256329 </ div >
257330 </ div >
@@ -273,7 +346,14 @@ export default function Dashboard(): JSX.Element {
273346 < div className = "animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500" > </ div >
274347 </ div >
275348 ) : (
276- < TaskWordCloud tasks = { [ ...activeTasks , ...allCompletedTasks ] } />
349+ < TaskWordCloud
350+ tasks = { selectedProjectIds . length > 0
351+ ? [
352+ ...( activeTasks ?. filter ( task => selectedProjectIds . includes ( task . projectId ) ) || [ ] ) ,
353+ ...( allCompletedTasks ?. filter ( task => selectedProjectIds . includes ( task . project_id ) ) || [ ] )
354+ ]
355+ : [ ...( activeTasks || [ ] ) , ...( allCompletedTasks || [ ] ) ] }
356+ />
277357 ) }
278358 </ div >
279359 </ div >
0 commit comments