1
1
import { Circle , Coins , ArrowRight , CircleCheck , ChevronDown , ChevronUp , Timer , Plus } from 'lucide-react'
2
+ import CompletionCountBadge from './CompletionCountBadge'
2
3
import {
3
4
ContextMenu ,
4
5
ContextMenuContent ,
@@ -9,7 +10,7 @@ import { cn, isHabitDueToday, getHabitFreq } from '@/lib/utils'
9
10
import Link from 'next/link'
10
11
import { useState , useEffect } from 'react'
11
12
import { useAtom } from 'jotai'
12
- import { pomodoroAtom , settingsAtom , completedHabitsMapAtom , browserSettingsAtom , BrowserSettings , hasTasksAtom } from '@/lib/atoms'
13
+ import { pomodoroAtom , settingsAtom , completedHabitsMapAtom , browserSettingsAtom , BrowserSettings , hasTasksAtom , dailyHabitsAtom } from '@/lib/atoms'
13
14
import { getTodayInTimezone , isSameDate , t2d , d2t , getNow } from '@/lib/utils'
14
15
import { Card , CardContent , CardHeader , CardTitle } from '@/components/ui/card'
15
16
import { Badge } from '@/components/ui/badge'
@@ -34,29 +35,15 @@ export default function DailyOverview({
34
35
} : UpcomingItemsProps ) {
35
36
const { completeHabit, undoComplete } = useHabits ( )
36
37
const [ settings ] = useAtom ( settingsAtom )
37
- const [ dailyHabits , setDailyHabits ] = useState < Habit [ ] > ( [ ] )
38
- const [ dailyTasks , setDailyTasks ] = useState < Habit [ ] > ( [ ] )
39
38
const [ completedHabitsMap ] = useAtom ( completedHabitsMapAtom )
39
+ const [ dailyItems ] = useAtom ( dailyHabitsAtom )
40
+ const dailyTasks = dailyItems . filter ( habit => habit . isTask )
41
+ const dailyHabits = dailyItems . filter ( habit => ! habit . isTask )
40
42
const today = getTodayInTimezone ( settings . system . timezone )
41
43
const todayCompletions = completedHabitsMap . get ( today ) || [ ]
42
44
const { saveHabit } = useHabits ( )
43
45
const [ browserSettings , setBrowserSettings ] = useAtom ( browserSettingsAtom )
44
46
45
- useEffect ( ( ) => {
46
- // Filter habits and tasks that are due today and not archived
47
- const filteredHabits = habits . filter ( habit =>
48
- ! habit . isTask &&
49
- ! habit . archived &&
50
- isHabitDueToday ( { habit, timezone : settings . system . timezone } )
51
- )
52
- const filteredTasks = habits . filter ( habit =>
53
- habit . isTask &&
54
- isHabitDueToday ( { habit, timezone : settings . system . timezone } )
55
- )
56
- setDailyHabits ( filteredHabits )
57
- setDailyTasks ( filteredTasks )
58
- } , [ habits ] )
59
-
60
47
// Get all wishlist items sorted by redeemable status (non-redeemable first) then by coin cost
61
48
// Filter out archived wishlist items
62
49
const sortedWishlistItems = wishlistItems
@@ -74,9 +61,6 @@ export default function DailyOverview({
74
61
return a . coinCost - b . coinCost
75
62
} )
76
63
77
- const [ expandedHabits , setExpandedHabits ] = useState ( false )
78
- const [ expandedTasks , setExpandedTasks ] = useState ( false )
79
- const [ expandedWishlist , setExpandedWishlist ] = useState ( false )
80
64
const [ hasTasks ] = useAtom ( hasTasksAtom )
81
65
const [ _ , setPomo ] = useAtom ( pomodoroAtom )
82
66
const [ modalConfig , setModalConfig ] = useState < {
@@ -126,13 +110,7 @@ export default function DailyOverview({
126
110
< h3 className = "font-semibold" > Daily Tasks</ h3 >
127
111
</ div >
128
112
< div className = "flex items-center gap-2" >
129
- < Badge variant = "secondary" >
130
- { `${ dailyTasks . filter ( task => {
131
- const completions = ( completedHabitsMap . get ( today ) || [ ] )
132
- . filter ( h => h . id === task . id ) . length ;
133
- return completions >= ( task . targetCompletions || 1 ) ;
134
- } ) . length } /${ dailyTasks . length } Completed`}
135
- </ Badge >
113
+ < CompletionCountBadge type = "tasks" />
136
114
< Button
137
115
variant = "ghost"
138
116
size = "sm"
@@ -149,7 +127,7 @@ export default function DailyOverview({
149
127
</ Button >
150
128
</ div >
151
129
</ div >
152
- < ul className = { `grid gap-2 transition-all duration-300 ease-in-out ${ expandedTasks ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
130
+ < ul className = { `grid gap-2 transition-all duration-300 ease-in-out ${ browserSettings . expandedTasks ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
153
131
{ dailyTasks
154
132
. sort ( ( a , b ) => {
155
133
// First by completion status
@@ -177,7 +155,7 @@ export default function DailyOverview({
177
155
const bTarget = b . targetCompletions || 1 ;
178
156
return bTarget - aTarget ;
179
157
} )
180
- . slice ( 0 , expandedTasks ? undefined : 5 )
158
+ . slice ( 0 , browserSettings . expandedTasks ? undefined : 5 )
181
159
. map ( ( habit ) => {
182
160
const completionsToday = habit . completions . filter ( completion =>
183
161
isSameDate ( t2d ( { timestamp : completion , timezone : settings . system . timezone } ) , t2d ( { timestamp : d2t ( { dateTime : getNow ( { timezone : settings . system . timezone } ) } ) , timezone : settings . system . timezone } ) )
@@ -279,10 +257,10 @@ export default function DailyOverview({
279
257
</ ul >
280
258
< div className = "flex items-center justify-between" >
281
259
< button
282
- onClick = { ( ) => setExpandedTasks ( ! expandedTasks ) }
260
+ onClick = { ( ) => setBrowserSettings ( prev => ( { ... prev , expandedTasks : ! prev . expandedTasks } ) ) }
283
261
className = "text-sm text-muted-foreground hover:text-primary flex items-center gap-1"
284
262
>
285
- { expandedTasks ? (
263
+ { browserSettings . expandedTasks ? (
286
264
< >
287
265
Show less
288
266
< ChevronUp className = "h-3 w-3" />
@@ -337,13 +315,7 @@ export default function DailyOverview({
337
315
< h3 className = "font-semibold" > Daily Habits</ h3 >
338
316
</ div >
339
317
< div className = "flex items-center gap-2" >
340
- < Badge variant = "secondary" >
341
- { `${ dailyHabits . filter ( habit => {
342
- const completions = ( completedHabitsMap . get ( today ) || [ ] )
343
- . filter ( h => h . id === habit . id ) . length ;
344
- return completions >= ( habit . targetCompletions || 1 ) ;
345
- } ) . length } /${ dailyHabits . length } Completed`}
346
- </ Badge >
318
+ < CompletionCountBadge type = "habits" />
347
319
< Button
348
320
variant = "ghost"
349
321
size = "sm"
@@ -360,7 +332,7 @@ export default function DailyOverview({
360
332
</ Button >
361
333
</ div >
362
334
</ div >
363
- < ul className = { `grid gap-2 transition-all duration-300 ease-in-out ${ expandedHabits ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
335
+ < ul className = { `grid gap-2 transition-all duration-300 ease-in-out ${ browserSettings . expandedHabits ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
364
336
{ dailyHabits
365
337
. sort ( ( a , b ) => {
366
338
// First by completion status
@@ -388,7 +360,7 @@ export default function DailyOverview({
388
360
const bTarget = b . targetCompletions || 1 ;
389
361
return bTarget - aTarget ;
390
362
} )
391
- . slice ( 0 , expandedHabits ? undefined : 5 )
363
+ . slice ( 0 , browserSettings . expandedHabits ? undefined : 5 )
392
364
. map ( ( habit ) => {
393
365
const completionsToday = habit . completions . filter ( completion =>
394
366
isSameDate ( t2d ( { timestamp : completion , timezone : settings . system . timezone } ) , t2d ( { timestamp : d2t ( { dateTime : getNow ( { timezone : settings . system . timezone } ) } ) , timezone : settings . system . timezone } ) )
@@ -490,10 +462,10 @@ export default function DailyOverview({
490
462
</ ul >
491
463
< div className = "flex items-center justify-between" >
492
464
< button
493
- onClick = { ( ) => setExpandedHabits ( ! expandedHabits ) }
465
+ onClick = { ( ) => setBrowserSettings ( prev => ( { ... prev , expandedHabits : ! prev . expandedHabits } ) ) }
494
466
className = "text-sm text-muted-foreground hover:text-primary flex items-center gap-1"
495
467
>
496
- { expandedHabits ? (
468
+ { browserSettings . expandedHabits ? (
497
469
< >
498
470
Show less
499
471
< ChevronUp className = "h-3 w-3" />
@@ -525,15 +497,15 @@ export default function DailyOverview({
525
497
</ Badge >
526
498
</ div >
527
499
< div >
528
- < div className = { `space-y-3 transition-all duration-300 ease-in-out ${ expandedWishlist ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
500
+ < div className = { `space-y-3 transition-all duration-300 ease-in-out ${ browserSettings . expandedWishlist ? 'max-h-none' : 'max-h-[200px]' } overflow-hidden` } >
529
501
{ sortedWishlistItems . length === 0 ? (
530
502
< div className = "text-center text-muted-foreground text-sm py-4" >
531
503
No wishlist items yet. Add some goals to work towards!
532
504
</ div >
533
505
) : (
534
506
< >
535
507
{ sortedWishlistItems
536
- . slice ( 0 , expandedWishlist ? undefined : 5 )
508
+ . slice ( 0 , browserSettings . expandedWishlist ? undefined : 5 )
537
509
. map ( ( item ) => {
538
510
const isRedeemable = item . coinCost <= coinBalance
539
511
return (
@@ -587,10 +559,10 @@ export default function DailyOverview({
587
559
</ div >
588
560
< div className = "flex items-center justify-between" >
589
561
< button
590
- onClick = { ( ) => setExpandedWishlist ( ! expandedWishlist ) }
562
+ onClick = { ( ) => setBrowserSettings ( prev => ( { ... prev , expandedWishlist : ! prev . expandedWishlist } ) ) }
591
563
className = "text-sm text-muted-foreground hover:text-primary flex items-center gap-1"
592
564
>
593
- { expandedWishlist ? (
565
+ { browserSettings . expandedWishlist ? (
594
566
< >
595
567
Show less
596
568
< ChevronUp className = "h-3 w-3" />
0 commit comments