@@ -226,9 +226,21 @@ interface LedgerTableProps {
226226type TableRow =
227227 | { type : "activity" ; dayDate : string ; showDate : boolean ; activity : LedgerDay [ "activities" ] [ number ] }
228228 | { type : "streak" ; dayDate : string ; showDate : boolean ; bonus : number }
229- | { type : "day_total" ; dayDate : string ; showDate : boolean ; day : LedgerDay }
229+ | { type : "day_total" ; dayDate : string ; showDate : boolean ; day : LedgerDay ; runningTotal : number }
230230 | { type : "grand_total" ; base : number ; bonus : number ; activityTotal : number ; streak : number ; total : number } ;
231231
232+ function getRunningTotalByDate ( days : LedgerDay [ ] ) {
233+ let runningTotal = 0 ;
234+ const runningTotals = new Map < string , number > ( ) ;
235+
236+ for ( const day of [ ...days ] . reverse ( ) ) {
237+ runningTotal += day . dayTotal ;
238+ runningTotals . set ( day . date , runningTotal ) ;
239+ }
240+
241+ return runningTotals ;
242+ }
243+
232244function LedgerTable ( {
233245 days,
234246 totalActivityBasePoints,
@@ -244,6 +256,7 @@ function LedgerTable({
244256
245257 const rows = useMemo ( ( ) => {
246258 const result : TableRow [ ] = [ ] ;
259+ const runningTotalsByDate = getRunningTotalByDate ( days ) ;
247260 for ( const day of days ) {
248261 let showDate = true ;
249262 for ( const activity of day . activities ) {
@@ -254,7 +267,13 @@ function LedgerTable({
254267 result . push ( { type : "streak" , dayDate : day . date , showDate, bonus : day . streakBonus } ) ;
255268 showDate = false ;
256269 }
257- result . push ( { type : "day_total" , dayDate : day . date , showDate, day } ) ;
270+ result . push ( {
271+ type : "day_total" ,
272+ dayDate : day . date ,
273+ showDate,
274+ day,
275+ runningTotal : runningTotalsByDate . get ( day . date ) ?? day . dayTotal ,
276+ } ) ;
258277 }
259278 result . push ( {
260279 type : "grand_total" ,
@@ -285,12 +304,14 @@ function LedgerTable({
285304 map . set ( `${ rowIdx } :4` , d . activityPoints ) ;
286305 map . set ( `${ rowIdx } :5` , d . streakBonus ) ;
287306 map . set ( `${ rowIdx } :6` , d . dayTotal ) ;
307+ map . set ( `${ rowIdx } :7` , row . runningTotal ) ;
288308 } else if ( row . type === "grand_total" ) {
289309 map . set ( `${ rowIdx } :2` , row . base ) ;
290310 map . set ( `${ rowIdx } :3` , row . bonus ) ;
291311 map . set ( `${ rowIdx } :4` , row . activityTotal ) ;
292312 map . set ( `${ rowIdx } :5` , row . streak ) ;
293313 map . set ( `${ rowIdx } :6` , row . total ) ;
314+ map . set ( `${ rowIdx } :7` , row . total ) ;
294315 }
295316 } ) ;
296317 return map ;
@@ -408,14 +429,14 @@ function LedgerTable({
408429 < div className = "overflow-x-auto" >
409430 < table
410431 ref = { tableRef }
411- className = "w-full min-w-[640px ] select-none border-x border-zinc-800 text-[13px]"
432+ className = "w-full min-w-[760px ] select-none border-x border-zinc-800 text-[13px]"
412433 style = { { borderCollapse : "collapse" } }
413434 onMouseDown = { handleCellMouseDown }
414435 onMouseMove = { handleTableMouseMove }
415436 >
416437 < tbody >
417438 < tr className = "sticky top-0 z-10 bg-zinc-900/95 backdrop-blur" >
418- { [ "Date" , "Activity" , "Base" , "Bonus" , "Total" , "Streak" , "Day Total" ] . map (
439+ { [ "Date" , "Activity" , "Base" , "Bonus" , "Total" , "Streak" , "Day Total" , "Running Total" ] . map (
419440 ( header ) => (
420441 < td
421442 key = { header }
@@ -513,6 +534,7 @@ function LedgerRow({
513534 { numCell ( 4 , a . pointsEarned , a . isNegative ? "text-red-400" : undefined ) }
514535 < td className = { cn ( CELL ) } />
515536 < td className = { cn ( CELL ) } />
537+ < td className = { cn ( CELL ) } />
516538 </ tr >
517539 ) ;
518540 }
@@ -529,6 +551,7 @@ function LedgerRow({
529551 < td className = { cn ( CELL ) } />
530552 { numCell ( 5 , row . bonus , "text-orange-400" ) }
531553 < td className = { cn ( CELL ) } />
554+ < td className = { cn ( CELL ) } />
532555 </ tr >
533556 ) ;
534557 }
@@ -548,6 +571,7 @@ function LedgerRow({
548571 { numCell ( 4 , d . activityPoints ) }
549572 { numCell ( 5 , d . streakBonus , "text-orange-400" ) }
550573 { numCell ( 6 , d . dayTotal ) }
574+ { numCell ( 7 , row . runningTotal ) }
551575 </ tr >
552576 ) ;
553577 }
@@ -574,6 +598,9 @@ function LedgerRow({
574598 < td data-row = { rowIdx } data-col = { 6 } className = { cn ( NUM_CELL , "cursor-cell" , selStyle ( 6 ) ) } >
575599 { fmt ( row . total ) }
576600 </ td >
601+ < td data-row = { rowIdx } data-col = { 7 } className = { cn ( NUM_CELL , "cursor-cell" , selStyle ( 7 ) ) } >
602+ { fmt ( row . total ) }
603+ </ td >
577604 </ tr >
578605 ) ;
579606}
@@ -591,6 +618,7 @@ const CSV_COLUMNS = [
591618 "total_points" ,
592619 "streak_bonus" ,
593620 "day_total" ,
621+ "running_total" ,
594622 "bonus_details" ,
595623 "notes" ,
596624] ;
@@ -616,6 +644,7 @@ function downloadLedgerCsv({
616644} ) {
617645 const header = [ ...CSV_COLUMNS ] ;
618646 const body : ( string | number ) [ ] [ ] = [ ] ;
647+ const runningTotalsByDate = getRunningTotalByDate ( days ) ;
619648
620649 for ( const day of days ) {
621650 for ( const a of day . activities ) {
@@ -628,6 +657,7 @@ function downloadLedgerCsv({
628657 a . pointsEarned ,
629658 "" ,
630659 "" ,
660+ "" ,
631661 a . triggeredBonuses ?. map ( ( b ) => b . description ) . join ( " | " ) ?? "" ,
632662 a . notes ?? "" ,
633663 ] ) ;
@@ -642,6 +672,7 @@ function downloadLedgerCsv({
642672 "" ,
643673 day . streakBonus ,
644674 "" ,
675+ "" ,
645676 `Day ${ day . streakBonus } streak` ,
646677 "" ,
647678 ] ) ;
@@ -655,6 +686,7 @@ function downloadLedgerCsv({
655686 day . activityPoints ,
656687 day . streakBonus ,
657688 day . dayTotal ,
689+ runningTotalsByDate . get ( day . date ) ?? day . dayTotal ,
658690 "" ,
659691 "" ,
660692 ] ) ;
@@ -669,6 +701,7 @@ function downloadLedgerCsv({
669701 totalActivityPoints ,
670702 totalStreakBonus ,
671703 totalPoints ,
704+ totalPoints ,
672705 "" ,
673706 "" ,
674707 ] ) ;
0 commit comments