Skip to content

Commit

Permalink
Created a dummy data file to add trannsactions in user accountn to ma…
Browse files Browse the repository at this point in the history
…ke development efficient
  • Loading branch information
Priyanshu9898 committed Dec 29, 2024
1 parent b8b9585 commit c0c047a
Show file tree
Hide file tree
Showing 7 changed files with 493 additions and 8 deletions.
62 changes: 62 additions & 0 deletions actions/Account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { DB } from "@/lib/prisma";
import { auth } from "@clerk/nextjs/server";

/* eslint-disable @typescript-eslint/no-explicit-any */

const serializeDecimal = (obj: any) => {
const serialized = { ...obj };
if (obj.balance) {
serialized.balance = obj.balance.toNumber();
}
if (obj.amount) {
serialized.amount = obj.amount.toNumber();
}
return serialized;
};

export async function getAccountDetails(acccountId: string) {
try {
const { userId } = await auth();

if (!userId) {
throw new Error("Unauthorized!!");
}

// Get accounts
const user = await DB.user.findUnique({
where: {
clerkUserId: userId,
},
});

if (!user) {
throw new Error("User not found");
}

const account = await DB.account.findUnique({
where: {
id: acccountId,
userId: user.id,
},
include: {
transactions: {
orderBy: {
createdAt: "desc",
},
},
_count: {
select: { transactions: true },
},
},
});

if (!account) return null;

return {
...serializeDecimal(account),
transactions: account.transactions.map(serializeDecimal),
};
} catch (error: any) {
console.error(error?.message);
}
}
155 changes: 155 additions & 0 deletions actions/seed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// app/account/[id]/seedTransactions.ts

"use server";

import { DB } from "@/lib/prisma";
import { subDays } from "date-fns";
import { v4 as uuidv4 } from "uuid"; // Using uuid library for broader compatibility

// Constants for account and user IDs
const ACCOUNT_ID = "4440ff34-e541-4f6d-a784-2e07a8c92cb6"; // Replace with actual account ID or use environment variables
const USER_ID = "9f09201a-dc5a-4bc8-afb0-2044ea947e77"; // Replace with actual user ID or use environment variables

// Define Category and Type interfaces
interface Category {
name: string;
range: [number, number];
}

interface Categories {
INCOME: Category[];
EXPENSE: Category[];
}

// Categories with their typical amount ranges
const CATEGORIES: Categories = {
INCOME: [
{ name: "salary", range: [5000, 8000] },
{ name: "freelance", range: [1000, 3000] },
{ name: "investments", range: [500, 2000] },
{ name: "other-income", range: [100, 1000] },
],
EXPENSE: [
{ name: "housing", range: [1000, 2000] },
{ name: "transportation", range: [100, 500] },
{ name: "groceries", range: [200, 600] },
{ name: "utilities", range: [100, 300] },
{ name: "entertainment", range: [50, 200] },
{ name: "food", range: [50, 150] },
{ name: "shopping", range: [100, 500] },
{ name: "healthcare", range: [100, 1000] },
{ name: "education", range: [200, 1000] },
{ name: "travel", range: [500, 2000] },
],
};

// Define TransactionStatus as a union of possible statuses
type TransactionStatus = "COMPLETED" | "PENDING" | "FAILED";

// Transaction interface
interface Transaction {
id: string;
type: "INCOME" | "EXPENSE";
amount: number;
description: string;
date: Date;
category: string;
status: TransactionStatus;
userId: string;
accountId: string;
createdAt: Date;
updatedAt: Date;
}

// Seed result interface
interface SeedResult {
success: boolean;
message?: string;
error?: string;
}

// Helper to generate random amount within a range
function getRandomAmount(min: number, max: number): number {
return Number((Math.random() * (max - min) + min).toFixed(2));
}

// Helper to get random category with amount
function getRandomCategory(type: keyof Categories): {
category: string;
amount: number;
} {
const categories = CATEGORIES[type];
const category = categories[Math.floor(Math.random() * categories.length)];
const amount = getRandomAmount(category.range[0], category.range[1]);
return { category: category.name, amount };
}

// Seed transactions function
export async function seedTransactions(): Promise<SeedResult> {
try {
// Generate 90 days of transactions
const transactions: Transaction[] = [];
let totalBalance = 0;

for (let i = 90; i >= 0; i--) {
const date = subDays(new Date(), i);

// Generate 1-3 transactions per day
const transactionsPerDay = Math.floor(Math.random() * 3) + 1;

for (let j = 0; j < transactionsPerDay; j++) {
// 40% chance of income, 60% chance of expense
const type: "INCOME" | "EXPENSE" =
Math.random() < 0.4 ? "INCOME" : "EXPENSE";
const { category, amount } = getRandomCategory(type);

const transaction: Transaction = {
id: uuidv4(), // Using uuidv4 for UUID generation
type,
amount,
description: `${
type === "INCOME" ? "Received" : "Paid for"
} ${category}`,
date,
category,
status: "COMPLETED", // Assuming all transactions are completed; adjust if needed
userId: USER_ID,
accountId: ACCOUNT_ID,
createdAt: date,
updatedAt: date,
};

totalBalance += type === "INCOME" ? amount : -amount;
transactions.push(transaction);
}
}

// Insert transactions in batches and update account balance
await DB.$transaction(async (tx) => {
// Clear existing transactions
await tx.transaction.deleteMany({
where: { accountId: ACCOUNT_ID },
});

// Insert new transactions
await tx.transaction.createMany({
data: transactions,
});

// Update account balance
await tx.account.update({
where: { id: ACCOUNT_ID },
data: { balance: totalBalance },
});
});

return {
success: true,
message: `Created ${transactions.length} transactions`,
};
} catch (error: any) {
console.error("Error seeding transactions:", error);
return { success: false, error: error.message };
}
}
84 changes: 80 additions & 4 deletions app/(main)/account/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,83 @@
import React from "react";
/* eslint-disable @typescript-eslint/no-explicit-any */
"// app/account/[id]/page.tsx";

const Account = () => {
return <div>Account</div>;
export const dynamic = "force-dynamic";

import { Suspense } from "react";
import { BarLoader } from "react-spinners";
import { notFound } from "next/navigation";
import { getAccountDetails } from "@/actions/Account";

// Define the Account interface
interface Account {
id: string;
name: string;
type: string;
balance: number;
_count: {
transactions: number;
};
transactions: any[];
}

const AccountPage = async ({ params }: { params: { id: string } }) => {
const parameters = await params;
const accountId = parameters.id;

const accountData: Account | null = await getAccountDetails(accountId);

if (!accountData) {
notFound();
}

const { transactions, ...account } = accountData;

console.log(transactions);

return (
<div className="container mx-auto py-8 px-5">
<div className="space-y-8 px-5">
<div className="flex gap-4 items-end justify-between space-y-0 pb-2">
<div>
<h1 className="text-3xl sm:text-5xl font-bold tracking-tight text-transparent bg-clip-text bg-gradient-to-r from-sky-500 to-blue-600 capitalize">
{account.name}
</h1>
<p className="text-muted-foreground ">
{account.type.charAt(0) + account.type.slice(1).toLowerCase()}{" "}
Account
</p>
</div>

<div className="text-right pb-2">
<div className="text-xl sm:text-2xl font-bold">
${account.balance.toFixed(2)}
</div>
<p className="text-sm text-muted-foreground">
{account._count.transactions} Transactions
</p>
</div>
</div>

{/* Chart Section */}
<Suspense
fallback={
<BarLoader className="mt-4" width={"100%"} color="#9333ea" />
}
>
{/* <AccountChart transactions={transactions} /> */}
</Suspense>

{/* Transactions Table */}
<Suspense
fallback={
<BarLoader className="mt-4" width={"100%"} color="#9333ea" />
}
>
{/* <TransactionTable transactions={transactions} /> */}
</Suspense>
</div>
</div>
);
};

export default Account;
export default AccountPage;
7 changes: 7 additions & 0 deletions app/api/seed/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { seedTransactions } from "@/actions/seed";

export async function GET() {
const result = await seedTransactions();

return Response.json(result);
}
Loading

0 comments on commit c0c047a

Please sign in to comment.