Skip to content

Commit

Permalink
feat: ✨ add transactions pie charts component
Browse files Browse the repository at this point in the history
  • Loading branch information
neopromic committed Nov 12, 2024
1 parent b85fb1d commit 6a21917
Show file tree
Hide file tree
Showing 10 changed files with 875 additions and 50 deletions.
20 changes: 20 additions & 0 deletions app/(authenticated)/dashboard/_components/percentage-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
interface PercentageItemProps {
icon: React.ReactNode;
title: string;
value: number;
}

const PercentageItem = ({ icon, title, value }: PercentageItemProps) => {
return (
<div className="flex items-center justify-between">
{/* Icone */}
<div className="flex items-center gap-2">
{icon}
<p>{title}</p>
</div>
<p className="text-sm font-bold">{value}%</p>
</div>
);
};

export default PercentageItem;
2 changes: 1 addition & 1 deletion app/(authenticated)/dashboard/_components/summar-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const SummaryCard = ({
size = "sm",
}: SummaryCardProps) => {
return (
<Card>
<Card className={`${size === "lg" ? "bg-white bg-opacity-10" : ""}`}>
<CardHeader className="flex-row items-center gap-2">
{icon}
<p
Expand Down
55 changes: 10 additions & 45 deletions app/(authenticated)/dashboard/_components/summary-cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,21 @@ import {
WalletIcon,
} from "lucide-react";
import SummaryCard from "./summar-card";
import { db } from "@/app/_lib/prisma";

interface SummaryCardsProps {
month: string;
balance: number;
investmentsTotal: number;
depositsTotal: number;
expensesTotal: number;
}

const SummaryCards = async ({ month }: SummaryCardsProps) => {
const where = {
date: {
gte: new Date(`2024-${month}-01`),
lt: new Date(`2024-${month}-31`),
},
};

const deposits = await db.transactions.aggregate({
where: {
type: "DEPOSIT",
...where,
},
_sum: {
amount: true,
},
});
const depositsTotal = deposits._sum.amount ?? 0;

const investments = await db.transactions.aggregate({
where: {
type: "INVESTMENT",
...where,
},
_sum: {
amount: true,
},
});
const investmentsTotal = investments._sum.amount ?? 0;

const expenses = await db.transactions.aggregate({
where: {
type: "EXPENSE",
...where,
},
_sum: {
amount: true,
},
});
const expensesTotal = expenses._sum.amount ?? 0;

const balance =
Number(depositsTotal) - Number(investmentsTotal) - Number(expensesTotal);

const SummaryCards = async ({
balance,
investmentsTotal,
depositsTotal,
expensesTotal,
}: SummaryCardsProps) => {
return (
<div className="space-y-6">
<SummaryCard
Expand Down
107 changes: 107 additions & 0 deletions app/(authenticated)/dashboard/_components/transactions-pie-chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"use client";

import * as React from "react";
import { Pie, PieChart } from "recharts";

import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/app/_components/ui/chart";
import { TransactionType } from "@prisma/client";
import { Card, CardContent } from "@/app/_components/ui/card";
import { PiggyBankIcon, TrendingDownIcon, TrendingUpIcon } from "lucide-react";
import type { TransactionPercentagesPerType } from "@/app/_data/get-dashboard/types";
import PercentageItem from "./percentage-item";

interface TransactionsPieChartProps {
depositsTotal: number;
investmentsTotal: number;
expensesTotal: number;
typesPercentages: TransactionPercentagesPerType;
}

const chartConfig = {
[TransactionType.INVESTMENT]: {
label: "Investido",
color: "#FFF",
},
[TransactionType.DEPOSIT]: {
label: "Receita",
color: "#55B02E",
},
[TransactionType.EXPENSE]: {
label: "Despesa",
color: "#E93030",
},
} satisfies ChartConfig;

const TransactionsPieChart = ({
depositsTotal,
investmentsTotal,
expensesTotal,
typesPercentages,
}: TransactionsPieChartProps) => {
const chartData = [
{
type: TransactionType.DEPOSIT,
amount: depositsTotal,
fill: "#55B02E",
},
{
type: TransactionType.INVESTMENT,
amount: investmentsTotal,
fill: "#FFF",
},
{
type: TransactionType.EXPENSE,
amount: expensesTotal,
fill: "#E93030",
},
];

return (
<Card className="flex flex-col py-12">
<CardContent className="flex-1 pb-0">
<ChartContainer
config={chartConfig}
className="mx-auto aspect-square max-h-[250px]"
>
<PieChart>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Pie
data={chartData}
dataKey="amount"
nameKey="type"
innerRadius={60}
strokeWidth={5}
></Pie>
</PieChart>
</ChartContainer>
<div className="space-y-2">
<PercentageItem
icon={<TrendingUpIcon size={16} className="text-primary" />}
title="Receita"
value={typesPercentages[TransactionType.DEPOSIT]}
/>
<PercentageItem
icon={<TrendingDownIcon size={16} className="text-danger" />}
title="Gastos"
value={typesPercentages[TransactionType.EXPENSE]}
/>
<PercentageItem
icon={<PiggyBankIcon size={16} className="text-white" />}
title="Investido"
value={typesPercentages[TransactionType.INVESTMENT]}
/>
</div>
</CardContent>
</Card>
);
};

export default TransactionsPieChart;
20 changes: 16 additions & 4 deletions app/(authenticated)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";
import SummaryCards from "./_components/summary-cards";
import TimeSelect from "./_components/time-select";
import TransactionsPieChart from "./_components/transactions-pie-chart";
import GetDashboard from "@/app/_data/get-dashboard";

interface HomeProps {
searchParams: {
Expand All @@ -24,13 +26,23 @@ const Home = async ({ searchParams: { month = "1" } }: HomeProps) => {
redirect("/dashboard?month=1");
}

const dashboard = await GetDashboard(monthNumber);

return (
<div className="space-y-6 p-6">
<div className="flex justify-between">
<h1 className="text-2xl font-bold">Dashboard</h1>
<TimeSelect defaultValue={month} />
<div className="grid grid-cols-[2fr,1fr]">
<div className="space-y-6">
<div className="flex justify-between">
<h1 className="text-2xl font-bold">Dashboard</h1>
<TimeSelect defaultValue={month} />
</div>
<SummaryCards month={monthNumber.toString()} {...dashboard} />

<div className="grid grid-cols-3 grid-rows-1 gap-6">
<TransactionsPieChart {...dashboard} />
</div>
</div>
</div>
<SummaryCards month={month} />
</div>
);
};
Expand Down
Loading

0 comments on commit 6a21917

Please sign in to comment.