aboutsummaryrefslogtreecommitdiffstats
path: root/src/app
diff options
context:
space:
mode:
authorSebastien Castiel <sebastien@castiel.me>2023-12-06 17:47:41 -0500
committerSebastien Castiel <sebastien@castiel.me>2023-12-06 18:57:35 -0500
commite747ec3ea02dd01e9ffa9e398e24e6939a5b738c (patch)
tree7f66d981effe2f51192ab7562d6c36ecdce459c1 /src/app
parent12b1cdb52a9d2723c319083b45a4e9a21896b3b4 (diff)
Tabs
Diffstat (limited to 'src/app')
-rw-r--r--src/app/groups/[groupId]/balances/page.tsx41
-rw-r--r--src/app/groups/[groupId]/expenses/page.tsx114
-rw-r--r--src/app/groups/[groupId]/group-tabs.tsx30
-rw-r--r--src/app/groups/[groupId]/layout.tsx20
-rw-r--r--src/app/groups/[groupId]/page.tsx132
-rw-r--r--src/app/layout.tsx2
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>