diff options
| author | Sebastien Castiel <sebastien@castiel.me> | 2023-12-06 17:47:41 -0500 |
|---|---|---|
| committer | Sebastien Castiel <sebastien@castiel.me> | 2023-12-06 18:57:35 -0500 |
| commit | e747ec3ea02dd01e9ffa9e398e24e6939a5b738c (patch) | |
| tree | 7f66d981effe2f51192ab7562d6c36ecdce459c1 /src/app | |
| parent | 12b1cdb52a9d2723c319083b45a4e9a21896b3b4 (diff) | |
Tabs
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/groups/[groupId]/balances/page.tsx | 41 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/expenses/page.tsx | 114 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/group-tabs.tsx | 30 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/layout.tsx | 20 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/page.tsx | 132 | ||||
| -rw-r--r-- | src/app/layout.tsx | 2 |
6 files changed, 197 insertions, 142 deletions
diff --git a/src/app/groups/[groupId]/balances/page.tsx b/src/app/groups/[groupId]/balances/page.tsx new file mode 100644 index 0000000..24818c9 --- /dev/null +++ b/src/app/groups/[groupId]/balances/page.tsx @@ -0,0 +1,41 @@ +import { BalancesList } from '@/app/groups/[groupId]/balances-list' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { getGroup, getGroupExpenses } from '@/lib/api' +import { getBalances } from '@/lib/balances' +import { notFound } from 'next/navigation' + +export default async function GroupPage({ + params: { groupId }, +}: { + params: { groupId: string } +}) { + const group = await getGroup(groupId) + if (!group) notFound() + + const expenses = await getGroupExpenses(groupId) + const balances = getBalances(expenses) + + return ( + <Card className="mb-4"> + <CardHeader> + <CardTitle>Balances</CardTitle> + <CardDescription> + This is the amount that each participant paid or was paid for. + </CardDescription> + </CardHeader> + <CardContent> + <BalancesList + balances={balances} + participants={group.participants} + currency={group.currency} + /> + </CardContent> + </Card> + ) +} diff --git a/src/app/groups/[groupId]/expenses/page.tsx b/src/app/groups/[groupId]/expenses/page.tsx new file mode 100644 index 0000000..2eb98ab --- /dev/null +++ b/src/app/groups/[groupId]/expenses/page.tsx @@ -0,0 +1,114 @@ +import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +import { getGroup, getGroupExpenses } from '@/lib/api' +import { ChevronRight, Plus } from 'lucide-react' +import Link from 'next/link' +import { notFound } from 'next/navigation' + +export default async function GroupExpensesPage({ + params: { groupId }, +}: { + params: { groupId: string } +}) { + const group = await getGroup(groupId) + if (!group) notFound() + + const expenses = await getGroupExpenses(groupId) + + return ( + <Card className="mb-4"> + <div className="flex flex-1"> + <CardHeader className="flex-1"> + <CardTitle>Expenses</CardTitle> + <CardDescription> + Here are the expenses that you created for your group. + </CardDescription> + </CardHeader> + <CardHeader> + <Button asChild size="icon"> + <Link href={`/groups/${groupId}/expenses/create`}> + <Plus /> + </Link> + </Button> + </CardHeader> + </div> + + <CardContent className="p-0"> + {expenses.length > 0 ? ( + <Table> + <TableHeader> + <TableRow> + <TableHead>Title</TableHead> + <TableHead>Paid by</TableHead> + <TableHead>Paid for</TableHead> + <TableHead className="text-right">Amount</TableHead> + <TableHead className="w-0"></TableHead> + </TableRow> + </TableHeader> + <TableBody> + {expenses.map((expense) => ( + <TableRow key={expense.id}> + <TableCell>{expense.title}</TableCell> + <TableCell> + <Badge variant="secondary"> + { + group.participants.find( + (p) => p.id === expense.paidById, + )?.name + } + </Badge> + </TableCell> + <TableCell className="flex flex-wrap gap-1"> + {expense.paidFor.map((paidFor, index) => ( + <Badge variant="secondary" key={index}> + { + group.participants.find( + (p) => p.id === paidFor.participantId, + )?.name + } + </Badge> + ))} + </TableCell> + <TableCell className="text-right tabular-nums whitespace-nowrap"> + {group.currency} {expense.amount.toFixed(2)} + </TableCell> + <TableCell> + <Button + size="icon" + variant="link" + className="-my-2" + asChild + > + <Link + href={`/groups/${groupId}/expenses/${expense.id}/edit`} + > + <ChevronRight className="w-4 h-4" /> + </Link> + </Button> + </TableCell> + </TableRow> + ))} + </TableBody> + </Table> + ) : ( + <div className="p-6">Your group doesn’t have any expense yet.</div> + )} + </CardContent> + </Card> + ) +} diff --git a/src/app/groups/[groupId]/group-tabs.tsx b/src/app/groups/[groupId]/group-tabs.tsx new file mode 100644 index 0000000..e5c48c2 --- /dev/null +++ b/src/app/groups/[groupId]/group-tabs.tsx @@ -0,0 +1,30 @@ +'use client' +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { usePathname, useRouter } from 'next/navigation' + +type Props = { + groupId: string +} + +export function GroupTabs({ groupId }: Props) { + const pathname = usePathname() + const value = + pathname.replace(/\/groups\/[^\/]+\/([^/]+).*/, '$1') || 'expenses' + const router = useRouter() + + return ( + <Tabs + value={value} + className="mb-4" + onValueChange={(value) => { + router.push(`/groups/${groupId}/${value}`) + }} + > + <TabsList> + <TabsTrigger value="expenses">Expenses</TabsTrigger> + <TabsTrigger value="balances">Balances</TabsTrigger> + <TabsTrigger value="edit">Settings</TabsTrigger> + </TabsList> + </Tabs> + ) +} diff --git a/src/app/groups/[groupId]/layout.tsx b/src/app/groups/[groupId]/layout.tsx index 5c835f5..5b99dd2 100644 --- a/src/app/groups/[groupId]/layout.tsx +++ b/src/app/groups/[groupId]/layout.tsx @@ -1,6 +1,8 @@ +import { GroupTabs } from '@/app/groups/[groupId]/group-tabs' +import { SaveGroupLocally } from '@/app/groups/[groupId]/save-recent-group' import { Button } from '@/components/ui/button' import { getGroup } from '@/lib/api' -import { ChevronLeft, Edit } from 'lucide-react' +import { ChevronLeft } from 'lucide-react' import Link from 'next/link' import { notFound } from 'next/navigation' import { PropsWithChildren } from 'react' @@ -24,19 +26,15 @@ export default async function GroupLayout({ </Button> </div> - <div className="flex justify-between items-baseline mb-4"> - <h1 className="font-bold text-2xl"> - <Link href={`/groups/${groupId}`}>{group.name}</Link> - </h1> + <h1 className="font-bold text-2xl mb-4"> + <Link href={`/groups/${groupId}`}>{group.name}</Link> + </h1> - <Button variant="outline" asChild size="icon"> - <Link href={`/groups/${groupId}/edit`}> - <Edit className="w-4 h-4" /> - </Link> - </Button> - </div> + <GroupTabs groupId={groupId} /> {children} + + <SaveGroupLocally group={{ id: group.id, name: group.name }} /> </> ) } diff --git a/src/app/groups/[groupId]/page.tsx b/src/app/groups/[groupId]/page.tsx index 7fffcb3..b28c3c9 100644 --- a/src/app/groups/[groupId]/page.tsx +++ b/src/app/groups/[groupId]/page.tsx @@ -1,137 +1,9 @@ -import { BalancesList } from '@/app/groups/[groupId]/balances-list' -import { SaveGroupLocally } from '@/app/groups/[groupId]/save-recent-group' -import { Badge } from '@/components/ui/badge' -import { Button } from '@/components/ui/button' -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from '@/components/ui/card' -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table' -import { getGroup, getGroupExpenses } from '@/lib/api' -import { getBalances } from '@/lib/balances' -import { ChevronRight, Plus } from 'lucide-react' -import Link from 'next/link' -import { notFound } from 'next/navigation' +import { redirect } from 'next/navigation' export default async function GroupPage({ params: { groupId }, }: { params: { groupId: string } }) { - const group = await getGroup(groupId) - if (!group) notFound() - - const expenses = await getGroupExpenses(groupId) - const balances = getBalances(expenses) - - return ( - <> - <Card className="mb-4"> - <div className="flex flex-1"> - <CardHeader className="flex-1"> - <CardTitle>Expenses</CardTitle> - <CardDescription> - Here are the expenses that you created for your group. - </CardDescription> - </CardHeader> - <CardHeader> - <Button asChild size="icon"> - <Link href={`/groups/${groupId}/expenses/create`}> - <Plus /> - </Link> - </Button> - </CardHeader> - </div> - - <CardContent className="p-0"> - {expenses.length > 0 ? ( - <Table> - <TableHeader> - <TableRow> - <TableHead>Title</TableHead> - <TableHead>Paid by</TableHead> - <TableHead>Paid for</TableHead> - <TableHead className="text-right">Amount</TableHead> - <TableHead className="w-0"></TableHead> - </TableRow> - </TableHeader> - <TableBody> - {expenses.map((expense) => ( - <TableRow key={expense.id}> - <TableCell>{expense.title}</TableCell> - <TableCell> - <Badge variant="secondary"> - { - group.participants.find( - (p) => p.id === expense.paidById, - )?.name - } - </Badge> - </TableCell> - <TableCell className="flex flex-wrap gap-1"> - {expense.paidFor.map((paidFor, index) => ( - <Badge variant="secondary" key={index}> - { - group.participants.find( - (p) => p.id === paidFor.participantId, - )?.name - } - </Badge> - ))} - </TableCell> - <TableCell className="text-right tabular-nums whitespace-nowrap"> - {group.currency} {expense.amount.toFixed(2)} - </TableCell> - <TableCell> - <Button - size="icon" - variant="link" - className="-my-2" - asChild - > - <Link - href={`/groups/${groupId}/expenses/${expense.id}/edit`} - > - <ChevronRight className="w-4 h-4" /> - </Link> - </Button> - </TableCell> - </TableRow> - ))} - </TableBody> - </Table> - ) : ( - <div className="p-6">Your group doesn’t have any expense yet.</div> - )} - </CardContent> - </Card> - - <Card className="mb-4"> - <CardHeader> - <CardTitle>Balances</CardTitle> - <CardDescription> - This is the amount that each participant paid or was paid for. - </CardDescription> - </CardHeader> - <CardContent> - <BalancesList - balances={balances} - participants={group.participants} - currency={group.currency} - /> - </CardContent> - </Card> - <SaveGroupLocally group={{ id: group.id, name: group.name }} /> - </> - ) + redirect(`/groups/${groupId}/expenses`) } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f580d66..7c5afbe 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -14,7 +14,7 @@ export default function RootLayout({ }) { return ( <html lang="en"> - <body className="bg-slate-50"> + <body className=""> <ProgressBar /> <div className="max-w-screen-md mx-auto p-4">{children}</div> </body> |
