From b8a7a5d6f44825eba9e0194990d3151a051dbd37 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Mon, 11 Mar 2024 03:38:30 +0100 Subject: [PATCH 1/5] N-FIN-12: add button to generate sample data --- src/app/account/page.tsx | 9 +- .../form/generateSampleDataForm.tsx | 25 +++ src/lib/actions/generateSampleData.ts | 190 ++++++++++++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 src/components/form/generateSampleDataForm.tsx create mode 100644 src/lib/actions/generateSampleData.ts diff --git a/src/app/account/page.tsx b/src/app/account/page.tsx index 38b1ae4..1b6d787 100644 --- a/src/app/account/page.tsx +++ b/src/app/account/page.tsx @@ -7,6 +7,8 @@ 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'; export default async function AccountPage() { @@ -37,7 +39,12 @@ export default async function AccountPage() { value={user?.username}/> - + + { + process.env.NODE_ENV === 'development' && ( + + ) + } diff --git a/src/components/form/generateSampleDataForm.tsx b/src/components/form/generateSampleDataForm.tsx new file mode 100644 index 0000000..b894137 --- /dev/null +++ b/src/components/form/generateSampleDataForm.tsx @@ -0,0 +1,25 @@ +'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)); + if (response.redirect) { + router.push(response.redirect); + } + }; + + return ( + + ); +} 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', + }; +} From 382df84510b86568e39a28b727e28bb6b1dd41b9 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Mon, 11 Mar 2024 03:52:44 +0100 Subject: [PATCH 2/5] N-FIN-12: refresh page after generation --- src/components/form/generateSampleDataForm.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/form/generateSampleDataForm.tsx b/src/components/form/generateSampleDataForm.tsx index b894137..25a0e29 100644 --- a/src/components/form/generateSampleDataForm.tsx +++ b/src/components/form/generateSampleDataForm.tsx @@ -14,9 +14,7 @@ export default function GenerateSampleDataForm({onSubmit}: { onSubmit: () => Pro const handleSubmit = async () => { const response = await onSubmit(); toast(sonnerContent(response)); - if (response.redirect) { - router.push(response.redirect); - } + router.refresh(); }; return ( From e83558dfefb9bb4848188ace931bfd7d101613ac Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Mon, 11 Mar 2024 03:53:13 +0100 Subject: [PATCH 3/5] N-FIN-12: add required shadcn/ui components --- package-lock.json | 24 ++++++++++++++++++++++++ package.json | 1 + src/components/ui/separator.tsx | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 src/components/ui/separator.tsx 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/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 }; From bb4f832d749582765fd2235fa6a6f624045628d6 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Mon, 11 Mar 2024 03:55:33 +0100 Subject: [PATCH 4/5] N-FIN-12: show account statistics --- src/app/account/page.tsx | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/app/account/page.tsx b/src/app/account/page.tsx index 1b6d787..4cd88f9 100644 --- a/src/app/account/page.tsx +++ b/src/app/account/page.tsx @@ -9,6 +9,7 @@ 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() { @@ -18,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 (
@@ -38,6 +61,26 @@ export default async function AccountPage() { disabled value={user?.username}/>
+
+
+ + +
+
+ + +
+
+ + +
+
{ From 63c2ea56e9709c5dcb36dd4990b0a4a3115e4bac Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Mon, 11 Mar 2024 03:55:47 +0100 Subject: [PATCH 5/5] N-FIN-12: move authentication cards to top --- src/app/auth/layout.tsx | 2 +- src/app/auth/signin/page.tsx | 2 +- src/app/auth/signup/page.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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.