diff --git a/package-lock.json b/package-lock.json
index 163fe2c..ab2c062 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
+ "@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-table": "^8.13.2",
"class-variance-authority": "^0.7.0",
@@ -1304,6 +1305,29 @@
}
}
},
+ "node_modules/@radix-ui/react-separator": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz",
+ "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
diff --git a/package.json b/package.json
index 216bd23..91f1598 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
+ "@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-table": "^8.13.2",
"class-variance-authority": "^0.7.0",
diff --git a/src/app/account/page.tsx b/src/app/account/page.tsx
index 38b1ae4..4cd88f9 100644
--- a/src/app/account/page.tsx
+++ b/src/app/account/page.tsx
@@ -7,6 +7,9 @@ import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import SignOutForm from '@/components/form/signOutForm';
import { URL_SIGN_IN } from '@/lib/constants';
+import GenerateSampleDataForm from '@/components/form/generateSampleDataForm';
+import generateSampleData from '@/lib/actions/generateSampleData';
+import { prismaClient } from '@/prisma';
export default async function AccountPage() {
@@ -16,6 +19,28 @@ export default async function AccountPage() {
redirect(URL_SIGN_IN);
}
+ let paymentCount = 0;
+ let entityCount = 0;
+ let categoryCount = 0;
+
+ if (process.env.NODE_ENV === 'development') {
+ paymentCount = await prismaClient.payment.count({
+ where: {
+ userId: user.id,
+ },
+ });
+ entityCount = await prismaClient.entity.count({
+ where: {
+ userId: user.id,
+ },
+ });
+ categoryCount = await prismaClient.category.count({
+ where: {
+ userId: user.id,
+ },
+ });
+ }
+
return (
@@ -36,8 +61,33 @@ export default async function AccountPage() {
disabled
value={user?.username}/>
+
-
+
+ {
+ process.env.NODE_ENV === 'development' && (
+
+ )
+ }
diff --git a/src/app/auth/layout.tsx b/src/app/auth/layout.tsx
index 729cb80..5aec572 100644
--- a/src/app/auth/layout.tsx
+++ b/src/app/auth/layout.tsx
@@ -6,7 +6,7 @@ export default function AuthLayout({
children: React.ReactNode;
}>) {
return (
-
+
{children}
);
diff --git a/src/app/auth/signin/page.tsx b/src/app/auth/signin/page.tsx
index f9a8e26..2660cbe 100644
--- a/src/app/auth/signin/page.tsx
+++ b/src/app/auth/signin/page.tsx
@@ -7,7 +7,7 @@ import { URL_SIGN_UP } from '@/lib/constants';
export default async function SignInPage() {
return (
-
+
Sign in
Sign into your existing account
diff --git a/src/app/auth/signup/page.tsx b/src/app/auth/signup/page.tsx
index 59ffc13..33ef08d 100644
--- a/src/app/auth/signup/page.tsx
+++ b/src/app/auth/signup/page.tsx
@@ -7,7 +7,7 @@ import { URL_SIGN_IN } from '@/lib/constants';
export default async function SignUpPage() {
return (
-
+
Sign up
Create a new account.
diff --git a/src/components/form/generateSampleDataForm.tsx b/src/components/form/generateSampleDataForm.tsx
new file mode 100644
index 0000000..25a0e29
--- /dev/null
+++ b/src/components/form/generateSampleDataForm.tsx
@@ -0,0 +1,23 @@
+'use client';
+
+import { Button } from '@/components/ui/button';
+import React from 'react';
+import { useRouter } from 'next/navigation';
+import { toast } from 'sonner';
+import { sonnerContent } from '@/components/ui/sonner';
+import { ActionResponse } from '@/lib/types/ActionResponse';
+
+export default function GenerateSampleDataForm({onSubmit}: { onSubmit: () => Promise }) {
+
+ const router = useRouter();
+
+ const handleSubmit = async () => {
+ const response = await onSubmit();
+ toast(sonnerContent(response));
+ router.refresh();
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
new file mode 100644
index 0000000..7c57343
--- /dev/null
+++ b/src/components/ui/separator.tsx
@@ -0,0 +1,31 @@
+'use client';
+
+import * as React from 'react';
+import * as SeparatorPrimitive from '@radix-ui/react-separator';
+
+import { cn } from '@/lib/utils';
+
+const Separator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(
+ (
+ {className, orientation = 'horizontal', decorative = true, ...props},
+ ref,
+ ) => (
+
+ ),
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
+
+export { Separator };
diff --git a/src/lib/actions/generateSampleData.ts b/src/lib/actions/generateSampleData.ts
new file mode 100644
index 0000000..5414f1e
--- /dev/null
+++ b/src/lib/actions/generateSampleData.ts
@@ -0,0 +1,190 @@
+import { prismaClient } from '@/prisma';
+import type { Category, Entity } from '@prisma/client';
+import { EntityType } from '@prisma/client';
+import { getUser } from '@/auth';
+import { URL_SIGN_IN } from '@/lib/constants';
+import { ActionResponse } from '@/lib/types/ActionResponse';
+
+export default async function generateSampleData(): Promise {
+ 'use server';
+
+ const user = await getUser();
+
+ if (!user) {
+ return {
+ type: 'error',
+ message: 'You must be logged in to create/update an category.',
+ redirect: URL_SIGN_IN,
+ };
+ }
+
+ // Categories: create sample data
+ const categories: Category[] = await prismaClient.category.findMany({where: {userId: user.id}});
+ if (await prismaClient.category.count({where: {userId: user.id}}) == 0) {
+
+ console.log('Creating sample categories...');
+
+ categories.push(await prismaClient.category.create({
+ data: {
+ userId: user.id,
+ name: 'Groceries',
+ color: '#FFBEAC',
+ },
+ }));
+
+ categories.push(await prismaClient.category.create({
+ data: {
+ userId: user.id,
+ name: 'Drugstore items',
+ color: '#9CBCFF',
+ },
+ }));
+
+ categories.push(await prismaClient.category.create({
+ data: {
+ userId: user.id,
+ name: 'Going out',
+ color: '#F1ADFF',
+ },
+ }));
+
+ categories.push(await prismaClient.category.create({
+ data: {
+ userId: user.id,
+ name: 'Random stuff',
+ color: '#C1FFA9',
+ },
+ }));
+
+ categories.push(await prismaClient.category.create({
+ data: {
+ userId: user.id,
+ name: 'Salary',
+ color: '#FFF787',
+ },
+ }));
+
+ console.log('Sample categories created.');
+ }
+ console.log(categories);
+
+ // Entities: create sample data
+ const entities: Entity[] = await prismaClient.entity.findMany({where: {userId: user.id}});
+ if (await prismaClient.entity.count({where: {userId: user.id}}) == 0) {
+
+ console.log('Creating sample entities...');
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Main Account',
+ type: EntityType.Account,
+ },
+ }));
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Company',
+ type: EntityType.Entity,
+ },
+ }));
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Supermarket 1',
+ type: EntityType.Entity,
+ },
+ }));
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Supermarket 2',
+ type: EntityType.Entity,
+ },
+ }));
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Supermarket 3',
+ type: EntityType.Entity,
+ },
+ }));
+
+ entities.push(await prismaClient.entity.create({
+ data: {
+ userId: user.id,
+ name: 'Supermarket 4',
+ type: EntityType.Entity,
+ },
+ }));
+
+ console.log('Sample entities created.');
+ }
+ console.log(entities);
+
+ // Payments: create sample data
+ console.log('Creating sample payments...');
+
+ if (await prismaClient.payment.count({where: {userId: user.id}}) == 0) {
+ for (let i = 0; i < 4; i++) {
+
+ const date = new Date();
+ date.setDate(1);
+ date.setMonth(date.getMonth() - i);
+
+ await prismaClient.payment.create({
+ data: {
+ userId: user.id,
+ amount: 200000,
+ date: date,
+ payorId: entities[1].id,
+ payeeId: entities[0].id,
+ categoryId: 5,
+ createdAt: date,
+ updatedAt: date,
+ },
+ });
+ }
+ }
+
+ let minAmount = 200; // 2€
+ let maxAmount = 3000; // 30€
+ let minPayee = entities[2].id;
+ let maxPayee = entities[entities.length - 1].id;
+ let minCategory = categories[0].id;
+ let maxCategory = categories[categories.length - 1].id;
+ let payments = 196;
+
+ for (let i = 0; i < payments; i++) {
+
+ const date = new Date(
+ new Date().getTime() - Math.floor(Math.random() * 10000000000));
+
+ await prismaClient.payment.create({
+ data: {
+ userId: user.id,
+ amount: Math.floor(
+ Math.random() * (maxAmount - minAmount) + minAmount),
+ date: date,
+ payorId: 1,
+ payeeId: Math.floor(
+ Math.random() * (maxPayee - minPayee) + minPayee),
+ categoryId: Math.floor(
+ Math.random() * (maxCategory - minCategory) + minCategory),
+ createdAt: date,
+ updatedAt: date,
+ },
+ });
+ }
+
+ console.log('Sample payments created.');
+
+ return {
+ type: 'success',
+ message: 'Sample data created',
+ };
+}