1- import Link from 'next/link' ;
1+ import { ActivityDto , AuthUserDto } from '@fairshare/shared-types' ;
2+
3+ import { ActivityList , QuickActions , SummaryCard } from '../../src/components/dashboard' ;
24import { DashboardLayout } from '../../src/components/layout' ;
35import { backendFetch } from '../../src/lib/backend' ;
46
57type Group = { id : string ; name : string ; currency : string } ;
8+ type Balance = { id : string ; userId : string ; counterpartyUserId : string ; amountCents : string } ;
9+
10+ function formatUsd ( cents : bigint ) : string {
11+ const dollars = Number ( cents ) / 100 ;
12+ return dollars . toLocaleString ( undefined , { style : 'currency' , currency : 'USD' } ) ;
13+ }
614
715export default async function DashboardPage ( ) {
8- let groups : Group [ ] = [ ] ;
9- try {
10- groups = await backendFetch < Group [ ] > ( '/groups' ) ;
11- } catch {
12- groups = [ ] ;
16+ const [ me , groups ] = await Promise . all ( [
17+ backendFetch < AuthUserDto > ( '/users/me' ) . catch ( ( ) => null ) ,
18+ backendFetch < Group [ ] > ( '/groups' ) . catch ( ( ) => [ ] as Group [ ] ) ,
19+ ] ) ;
20+
21+ const activeGroupId = groups [ 0 ] ?. id ;
22+
23+ const [ balances , activity ] = await Promise . all ( [
24+ activeGroupId
25+ ? backendFetch < Balance [ ] > ( `/groups/${ activeGroupId } /balances` ) . catch ( ( ) => [ ] as Balance [ ] )
26+ : Promise . resolve ( [ ] as Balance [ ] ) ,
27+ activeGroupId
28+ ? backendFetch < ActivityDto [ ] > ( `/groups/${ activeGroupId } /activity?cursor=0&limit=5` ) . catch ( ( ) => [ ] as ActivityDto [ ] )
29+ : Promise . resolve ( [ ] as ActivityDto [ ] ) ,
30+ ] ) ;
31+
32+ let oweCents = 0n ;
33+ let owedToMeCents = 0n ;
34+ if ( me ) {
35+ for ( const bal of balances ) {
36+ if ( bal . userId !== me . id ) continue ;
37+ const amt = BigInt ( bal . amountCents ) ;
38+ if ( amt < 0n ) oweCents += - amt ;
39+ else owedToMeCents += amt ;
40+ }
1341 }
1442
1543 return (
1644 < DashboardLayout >
1745 < section className = "grid gap-4 md:grid-cols-3" >
18- < Link href = "/dashboard/groups" className = "rounded-2xl border border-border bg-card p-5 shadow-glass backdrop-blur-glass" >
19- < h2 className = "font-semibold text-text-primary" > Groups</ h2 >
20- < p className = "mt-1 text-sm text-text-secondary" > { groups . length } total groups</ p >
21- </ Link >
22- < div className = "rounded-2xl border border-border bg-card p-5 shadow-glass backdrop-blur-glass" >
23- < h2 className = "font-semibold text-text-primary" > Quick actions</ h2 >
24- < p className = "mt-1 text-sm text-text-secondary" > Create expenses and settle balances.</ p >
25- </ div >
26- < div className = "rounded-2xl border border-border bg-card p-5 shadow-glass backdrop-blur-glass" >
27- < h2 className = "font-semibold text-text-primary" > Recent activity</ h2 >
28- < p className = "mt-1 text-sm text-text-secondary" > Coming next.</ p >
29- </ div >
46+ < SummaryCard title = "Groups" value = { groups . length } hint = "Your active groups" />
47+ < SummaryCard
48+ title = "You owe"
49+ value = { formatUsd ( oweCents ) }
50+ hint = { activeGroupId ? `Based on ${ activeGroupId } ` : 'No group selected' }
51+ />
52+ < SummaryCard
53+ title = "You are owed"
54+ value = { formatUsd ( owedToMeCents ) }
55+ hint = { me ? `Signed in as ${ me . email } ` : 'Session active' }
56+ />
57+ </ section >
58+
59+ < section className = "grid gap-4 md:grid-cols-[1.2fr_0.8fr]" >
60+ { activeGroupId ? (
61+ < ActivityList groupId = { activeGroupId } items = { activity } />
62+ ) : (
63+ < div className = "rounded-2xl border border-border bg-card p-5 text-sm text-text-secondary shadow-glass backdrop-blur-glass" >
64+ Create or join a group to see activity.
65+ </ div >
66+ ) }
67+ < QuickActions groupId = { activeGroupId } />
3068 </ section >
3169 </ DashboardLayout >
3270 ) ;
33- }
71+ }
0 commit comments