diff --git a/prisma/migrations/20240317102723_add_default_category_to_entity/migration.sql b/prisma/migrations/20240317102723_add_default_category_to_entity/migration.sql new file mode 100644 index 0000000..f7767eb --- /dev/null +++ b/prisma/migrations/20240317102723_add_default_category_to_entity/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "entities" + ADD COLUMN "default_category_id" INTEGER; + +-- AddForeignKey +ALTER TABLE "entities" + ADD CONSTRAINT "entities_default_category_id_fkey" FOREIGN KEY ("default_category_id") REFERENCES "categories" ("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5d51152..1e9f6e1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,13 +34,15 @@ model Session { } model Entity { - id Int @id @default(autoincrement()) - userId String @map("user_id") - user User @relation(fields: [userId], references: [id]) - name String - type EntityType - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") + id Int @id @default(autoincrement()) + userId String @map("user_id") + user User @relation(fields: [userId], references: [id]) + name String + type EntityType + defaultCategory Category? @relation(fields: [defaultCategoryId], references: [id]) + defaultCategoryId Int? @map("default_category_id") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") paymentsAsPayor Payment[] @relation("PayorEntity") paymentsAsPayee Payment[] @relation("PayeeEntity") @@ -84,6 +86,7 @@ model Category { updatedAt DateTime @updatedAt @map("updated_at") payments Payment[] + Entity Entity[] @@unique(fields: [userId, name]) @@map("categories") diff --git a/src/app/entities/columns.tsx b/src/app/entities/columns.tsx index 90b3754..c68da1b 100644 --- a/src/app/entities/columns.tsx +++ b/src/app/entities/columns.tsx @@ -1,12 +1,13 @@ 'use client'; import { ColumnDef } from '@tanstack/react-table'; -import { Entity } from '@prisma/client'; +import { Category, Entity } from '@prisma/client'; import { CellContext, ColumnDefTemplate } from '@tanstack/table-core'; import { format } from 'date-fns'; export const columns = ( actionCell: ColumnDefTemplate>, + categories: Category[], ) => { return [ @@ -19,6 +20,30 @@ export const columns = ( header: 'Type', size: 100, }, + { + accessorKey: 'defaultCategoryId', + header: 'Default Category', + cell: ({row}) => { + const category = categories.find((category) => category.id === row.original.defaultCategoryId); + return ( + <> + { + category && ( +
+ + + +

{category?.name ?? '-'}

+
+ ) + } + + + ); + }, + size: 200, + }, { accessorKey: 'createdAt', header: 'Created at', diff --git a/src/app/entities/page.tsx b/src/app/entities/page.tsx index 6f41ba5..f5b7d0a 100644 --- a/src/app/entities/page.tsx +++ b/src/app/entities/page.tsx @@ -23,9 +23,24 @@ export default async function EntitiesPage() { ], }); + const categories = await prismaClient.category.findMany({ + where: { + userId: user?.id, + }, + orderBy: [ + { + name: 'asc', + }, + { + id: 'asc', + }, + ], + }); + return ( diff --git a/src/components/entityPageClientComponents.tsx b/src/components/entityPageClientComponents.tsx index 3845ee1..f3f3085 100644 --- a/src/components/entityPageClientComponents.tsx +++ b/src/components/entityPageClientComponents.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Entity } from '@prisma/client'; +import { Category, Entity } from '@prisma/client'; import React, { useState } from 'react'; import { CellContext } from '@tanstack/table-core'; import { Button } from '@/components/ui/button'; @@ -27,8 +27,9 @@ import { import { useMediaQuery } from '@/lib/hooks/useMediaQuery'; import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer'; -export default function EntityPageClientContent({entities, onSubmit, onDelete, className}: { +export default function EntityPageClientContent({entities, categories, onSubmit, onDelete, className}: { entities: Entity[], + categories: Category[], onSubmit: (data: z.infer) => Promise, onDelete: (id: number) => Promise, className: string, @@ -146,6 +147,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c @@ -167,6 +169,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c @@ -184,7 +187,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c {/* Data Table */} diff --git a/src/components/form/entityForm.tsx b/src/components/form/entityForm.tsx index 274c290..953aca8 100644 --- a/src/components/form/entityForm.tsx +++ b/src/components/form/entityForm.tsx @@ -12,11 +12,13 @@ import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; import { sonnerContent } from '@/components/ui/sonner'; import { entityFormSchema } from '@/lib/form-schemas/entityFormSchema'; -import { Entity, EntityType } from '@prisma/client'; +import { Category, Entity, EntityType } from '@prisma/client'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { AutoCompleteInput } from '@/components/ui/auto-complete-input'; -export default function EntityForm({value, onSubmit, className}: { +export default function EntityForm({value, categories, onSubmit, className}: { value: Entity | undefined, + categories: Category[], onSubmit: (data: z.infer) => Promise className?: string }) { @@ -29,6 +31,7 @@ export default function EntityForm({value, onSubmit, className}: { id: value?.id ?? undefined, name: value?.name ?? '', type: value?.type ?? EntityType.Entity, + defaultCategoryId: value?.defaultCategoryId ?? undefined, }, }); @@ -40,6 +43,13 @@ export default function EntityForm({value, onSubmit, className}: { } }; + const categoriesMapped = categories?.map((category) => { + return { + label: category.name, + value: category.id, + }; + }) ?? []; + return (
@@ -94,6 +104,22 @@ export default function EntityForm({value, onSubmit, className}: { )} /> + ( + + Category + + + + + + )} + /> diff --git a/src/components/form/paymentForm.tsx b/src/components/form/paymentForm.tsx index 705587e..5e9c44d 100644 --- a/src/components/form/paymentForm.tsx +++ b/src/components/form/paymentForm.tsx @@ -166,7 +166,17 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas placeholder="Select payee" items={entitiesMapped} next={categoryRef} - {...field} /> + {...field} + onChange={(e) => { + field.onChange(e); + if (e && e.target.value) { + const entity = entities.find((entity) => entity.id === Number(e.target.value)); + console.log(entity?.defaultCategoryId); + if (entity?.defaultCategoryId !== null) { + form.setValue('categoryId', entity?.defaultCategoryId); + } + } + }}/> diff --git a/src/components/ui/auto-complete-input.tsx b/src/components/ui/auto-complete-input.tsx index 29363e6..1119e74 100644 --- a/src/components/ui/auto-complete-input.tsx +++ b/src/components/ui/auto-complete-input.tsx @@ -13,12 +13,12 @@ export interface AutoCompleteInputProps const AutoCompleteInput = React.forwardRef( ({className, type, ...props}, ref) => { - const [value, setValue] = useState(getInitialValue()); + const [value, setValue] = useState(getNameOfPropValue()); const [open, setOpen] = useState(false); const [lastKey, setLastKey] = useState(''); const [filteredItems, setFilteredItems] = useState(props.items); - function getInitialValue() { + function getNameOfPropValue() { if (!props.items) { return ''; @@ -50,6 +50,15 @@ const AutoCompleteInput = React.forwardRef { + console.log('Prop value changed', value, props.value); + if (props.value) { + setValue(getNameOfPropValue()); + } else { + setValue(''); + } + }, [props.value]); + return (
): Promise { 'use server'; @@ -32,6 +33,7 @@ export default async function entityCreateUpdate({ data: { name: name, type: type, + defaultCategoryId: defaultCategoryId, }, }, ); @@ -47,6 +49,7 @@ export default async function entityCreateUpdate({ userId: user.id, name: name, type: type, + defaultCategoryId: defaultCategoryId, }, }); diff --git a/src/lib/form-schemas/entityFormSchema.ts b/src/lib/form-schemas/entityFormSchema.ts index f3e4412..d7b80b6 100644 --- a/src/lib/form-schemas/entityFormSchema.ts +++ b/src/lib/form-schemas/entityFormSchema.ts @@ -5,4 +5,5 @@ export const entityFormSchema = z.object({ id: z.number().positive().optional(), name: z.string().min(1).max(32), type: z.nativeEnum(EntityType), + defaultCategoryId: z.number().positive().optional(), });