Skip to content

Commit

Permalink
Add tRPC, use it for group expenses, balances and information page (#246
Browse files Browse the repository at this point in the history
)

* Add tRPC, use it for group expense list

* Use tRPC for balances

* Use tRPC in group information + better loading states
  • Loading branch information
scastiel authored Oct 19, 2024
1 parent 727803e commit 66e15e4
Show file tree
Hide file tree
Showing 24 changed files with 672 additions and 240 deletions.
136 changes: 132 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@tailwindcss/typography": "^0.5.10",
"@tanstack/react-query": "^5.59.15",
"@trpc/client": "^11.0.0-rc.586",
"@trpc/react-query": "^11.0.0-rc.586",
"@trpc/server": "^11.0.0-rc.586",
"class-variance-authority": "^0.7.0",
"client-only": "^0.0.1",
"clsx": "^2.0.0",
"cmdk": "^0.2.0",
"content-disposition": "^0.5.4",
Expand All @@ -54,13 +59,16 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.47.0",
"react-intersection-observer": "^9.8.0",
"server-only": "^0.0.1",
"sharp": "^0.33.2",
"superjson": "^2.2.1",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"ts-pattern": "^5.0.6",
"use-debounce": "^10.0.4",
"uuid": "^9.0.1",
"vaul": "^0.8.0",
"zod": "^3.22.4"
"zod": "^3.23.8"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
Expand Down
13 changes: 13 additions & 0 deletions src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createTRPCContext } from '@/trpc/init'
import { appRouter } from '@/trpc/routers/_app'
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'

const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext: createTRPCContext,
})

export { handler as GET, handler as POST }
138 changes: 138 additions & 0 deletions src/app/groups/[groupId]/balances/balances-and-reimbursements.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
'use client'

import { BalancesList } from '@/app/groups/[groupId]/balances-list'
import { ReimbursementList } from '@/app/groups/[groupId]/reimbursement-list'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { Skeleton } from '@/components/ui/skeleton'
import { getGroup } from '@/lib/api'
import { trpc } from '@/trpc/client'
import { useTranslations } from 'next-intl'
import { Fragment, useEffect } from 'react'

export default function BalancesAndReimbursements({
group,
}: {
group: NonNullable<Awaited<ReturnType<typeof getGroup>>>
}) {
const utils = trpc.useUtils()

useEffect(() => {
// Until we use tRPC more widely and can invalidate the cache on expense
// update, it's easier and safer to invalidate the cache on page load.
utils.groups.balances.invalidate()
}, [utils])

const t = useTranslations('Balances')

const { data, isLoading } = trpc.groups.balances.list.useQuery({
groupId: group.id,
})

return (
<>
<Card className="mb-4">
<CardHeader>
<CardTitle>{t('title')}</CardTitle>
<CardDescription>{t('description')}</CardDescription>
</CardHeader>
<CardContent>
{isLoading || !data ? (
<BalancesLoading participantCount={group.participants.length} />
) : (
<BalancesList
balances={data.balances}
participants={group.participants}
currency={group.currency}
/>
)}
</CardContent>
</Card>
<Card className="mb-4">
<CardHeader>
<CardTitle>{t('Reimbursements.title')}</CardTitle>
<CardDescription>{t('Reimbursements.description')}</CardDescription>
</CardHeader>
<CardContent>
{isLoading || !data ? (
<ReimbursementsLoading
participantCount={group.participants.length}
/>
) : (
<ReimbursementList
reimbursements={data.reimbursements}
participants={group.participants}
currency={group.currency}
groupId={group.id}
/>
)}
</CardContent>
</Card>
</>
)
}

const ReimbursementsLoading = ({
participantCount,
}: {
participantCount: number
}) => {
return (
<div className="flex flex-col">
{Array(participantCount - 1)
.fill(undefined)
.map((_, index) => (
<div key={index} className="flex justify-between py-5">
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4">
<Skeleton className="h-3 w-32" />
<Skeleton className="h-3 w-24" />
</div>
<Skeleton className="h-3 w-16" />
</div>
))}
</div>
)
}

const BalancesLoading = ({
participantCount,
}: {
participantCount: number
}) => {
return (
<div className="grid grid-cols-2 py-1 gap-y-2">
{Array(participantCount)
.fill(undefined)
.map((_, index) =>
index % 2 === 0 ? (
<Fragment key={index}>
<div className="flex items-center justify-end pr-2">
<Skeleton className="h-3 w-16" />
</div>
<div className="self-start">
<Skeleton
className={`h-7 w-${(index % 3) + 1}/3 rounded-l-none`}
/>
</div>
</Fragment>
) : (
<Fragment key={index}>
<div className="flex items-center justify-end">
<Skeleton
className={`h-7 w-${(index % 3) + 1}/3 rounded-r-none`}
/>
</div>
<div className="flex items-center pl-2">
<Skeleton className="h-3 w-16" />
</div>
</Fragment>
),
)}
</div>
)
}
Loading

0 comments on commit 66e15e4

Please sign in to comment.