Skip to content

Commit

Permalink
Merge pull request #13 from zefhub/analytics
Browse files Browse the repository at this point in the history
Analytics page
  • Loading branch information
thedanielforum authored May 23, 2022
2 parents fb886b3 + e3316c6 commit 463728a
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 112 deletions.
2 changes: 2 additions & 0 deletions components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface ButtonProps {
type: "button" | "submit" | "reset";
onClick?: MouseEventHandler<HTMLButtonElement>;
className?: string;
style?: any;
}

const Button: React.FC<ButtonProps> = (props) => {
Expand All @@ -15,6 +16,7 @@ const Button: React.FC<ButtonProps> = (props) => {
"h-12 px-6 rounded-full drop-shadow-lg",
props.className,
].join(" ")}
style={props.style}
>
{props.children}
</button>
Expand Down
15 changes: 9 additions & 6 deletions forms/TransactionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ const TransactionForm: React.FC<TransactionFormProps> = (props) => {
className="mb-4"
/>
{!data.queryCategory.length ? (
<Link href="/account/categories">
<a className="self-center px-6 py-6 mt-12 mb-12 rounded-full drop-shadow-lg bg-gradient-to-br from-ikura-light to-ikura-dark text-white">
Add category
</a>
</Link>
<div className="flex flex-row justify-center w-full">
<Link href="/account/categories">
<a className="self-center px-6 py-6 mt-12 mb-12 rounded-full drop-shadow-lg bg-gradient-to-br from-ikura-light to-ikura-dark text-white">
Add category
</a>
</Link>
</div>
) : (
<div className="mb-4 w-full flex flex-col items-start">
<h3 className="font-semibold">Select category</h3>
Expand All @@ -89,7 +91,8 @@ const TransactionForm: React.FC<TransactionFormProps> = (props) => {
<div className="flex flex-row justify-between w-full">
<Button
type="button"
className="bg-gradient-to-br from-ikura-light to-ikura-dark text-white mt-2"
className="text-white mt-2"
style={{ backgroundColor: "#2ecc71" }}
onClick={() => {
form.setValues({ ...form.values, type: "income" });
form.handleSubmit();
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@
"graphql": "^16.3.0",
"jsonwebtoken": "^8.5.1",
"lodash.isequal": "^4.5.0",
"luxon": "^2.0.2",
"luxon": "^2.4.0",
"next": "11.1.2",
"next-absolute-url": "^1.2.2",
"next-auth": "^4.3.4",
"react": "17.0.2",
"react-css-collapse": "^4.1.0",
"react-dom": "17.0.2",
"react-hot-toast": "^2.2.0",
"react-hotkeys-hook": "^3.4.3",
"react-hotkeys-hook": "^3.4.6",
"react-intl": "^5.20.13",
"react-select": "^5.1.0",
"recharts": "^2.1.9",
"sass": "^1.42.1",
"yup": "^0.32.9"
"yup": "^0.32.11"
},
"devDependencies": {
"@formatjs/cli": "^4.3.2",
Expand All @@ -73,7 +73,7 @@
"eslint-plugin-testing-library": "5.0.1",
"jest": "27.4.5",
"postcss": "^8.4.12",
"tailwindcss": "^3.0.23",
"tailwindcss": "^3.0.24",
"typescript": "4.4.3"
}
}
175 changes: 117 additions & 58 deletions pages/analytics.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,68 @@
import type { NextPage } from "next";
import { useIntl } from "react-intl";
import { PieChart, Pie, Sector, Cell, ResponsiveContainer } from "recharts";
import { useQuery, gql } from "@apollo/client";
import { PieChart, Pie, LabelList } from "recharts";
import Dinero from "dinero.js";
import Protected from "components/Protected";
import Loading from "components/Loading";

const data = [
{ name: "Group A", value: 400 },
{ name: "Group B", value: 300 },
{ name: "Group C", value: 300 },
{ name: "Group D", value: 200 },
];
const GET_CATEGORY_CHART_DATA = gql`
query categoryChartData {
queryTransaction {
id
amount
category {
id
icon
name
}
}
}
`;

const COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"];
const Analytics: NextPage = () => {
const intl = useIntl();
const {
data: pieChartData,
loading,
error,
} = useQuery(GET_CATEGORY_CHART_DATA, {});
if (error) {
console.error(error);
}

const RADIAN = Math.PI / 180;
const renderCustomizedLabel = ({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
percent,
index,
}: any) => {
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
const x = cx + radius * Math.cos(-midAngle * RADIAN);
const y = cy + radius * Math.sin(-midAngle * RADIAN);
const formatChartData = () => {
let data: {
name: string;
icon: string;
value: number;
categoryId: string;
}[] = [];

return (
<text
x={x}
y={y}
fill="white"
textAnchor={x > cx ? "start" : "end"}
dominantBaseline="central"
>
{`${(percent * 100).toFixed(0)}%`}
</text>
);
};
if (!pieChartData || !pieChartData.queryTransaction) {
return data;
}

const Analytics: NextPage = () => {
const intl = useIntl();
pieChartData.queryTransaction.forEach((item: any) => {
const categoryIndex = data.findIndex(
(c) => c.categoryId === item.category.id
);
if (item.amount < 0) {
if (categoryIndex !== -1) {
data[categoryIndex].value += Math.abs(item.amount);
} else {
data.push({
icon: item.category.icon,
name: item.category.name,
value: Math.abs(item.amount),
categoryId: item.category.id,
});
}
}
});

return data;
};

return (
<Protected>
Expand All @@ -51,29 +73,66 @@ const Analytics: NextPage = () => {
</h1>
</div>
</div>
<div className="flex flex-col items-center">
{/*
<PieChart width={300} height={300}>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={renderCustomizedLabel}
outerRadius={80}
fill="#8884d8"
dataKey="value"
>
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={COLORS[index % COLORS.length]}
/>
))}
</Pie>
</PieChart>
*/}
<h1 className="mt-12">coming soon</h1>
<div className="flex flex-col justify-start items-center">
{loading ? (
<Loading />
) : (
<div>
<PieChart width={300} height={300}>
<Pie
data={formatChartData()}
dataKey="value"
nameKey="icon"
cx="50%"
cy="50%"
innerRadius={50}
outerRadius={80}
fill="#82ca9d"
// label
>
<LabelList
dataKey="icon"
position="outside"
offset={5}
color="#000"
fill="#000"
fontSize={23}
fontWeight="bold"
// formatter={(value: any) => {
// console.log("value", value);
// return value;
// }}
/>
</Pie>
</PieChart>
<div>
<h2 className="text-lg font-semibold">
{intl.formatMessage({ defaultMessage: "Spend by category" })}
</h2>
{formatChartData().map((item: any) => (
<div
key={`row-${item.categoryId}`}
className="flex flex-row justify-between items-center py-2"
>
<div className="flex flex-row">
<div className="flex flex-row justify-center items-center w-12 h-12 bg-blue-100 rounded-lg">
<span className="text-3xl">{item.icon}</span>
</div>
<div className="flex flex-col justify-center ml-2">
<h1 className="font-semibold">{item.name}</h1>
</div>
</div>
<h1 className="text-lg font-semibold text-red-500">
-&nbsp;
{Dinero({ amount: item.value, precision: 2 }).toFormat(
"$0,0.00"
)}
</h1>
</div>
))}
</div>
</div>
)}
</div>
</Protected>
);
Expand Down
9 changes: 6 additions & 3 deletions pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export default NextAuth({
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
httpOptions: {
timeout: 40000,
},
}),
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID as string,
Expand Down Expand Up @@ -60,14 +63,14 @@ export default NextAuth({
let user: any = {};

// During initial flow the token does not have any user data.
if (token?.email) {
if (token?.email !== "") {
// Register user on zefhub to get uid.
const serverToken = await jwt.sign(
{ ...token, aud: "ikura.app", admin: true },
secret,
{
algorithm: "HS256",
expiresIn: "1h",
expiresIn: "12h",
}
);

Expand Down Expand Up @@ -110,7 +113,7 @@ export default NextAuth({
...token,
...user,
aud: "ikura.app",
iss: "https://www.ikura.app",
// iss: "https://www.ikura.app",
},
secret,
{
Expand Down
Loading

1 comment on commit 463728a

@vercel
Copy link

@vercel vercel bot commented on 463728a May 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ikura – ./

ikura.vercel.app
www.ikura.app
ikura-zefhub.vercel.app
ikura-git-main-zefhub.vercel.app
ikura.app

Please sign in to comment.