From 87ffc649959b02a3d98585f9b7376c328cac5bde Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Wed, 13 Mar 2024 22:49:05 +0100 Subject: [PATCH 01/17] N-FIN-32: move padding to global layout --- src/app/categories/page.tsx | 2 +- src/app/entities/page.tsx | 2 +- src/app/layout.tsx | 4 ++-- src/app/page.tsx | 2 +- src/app/payments/page.tsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/categories/page.tsx b/src/app/categories/page.tsx index d460ade..f7bee73 100644 --- a/src/app/categories/page.tsx +++ b/src/app/categories/page.tsx @@ -25,6 +25,6 @@ export default async function CategoriesPage() { categories={categories} onSubmit={categoryCreateUpdate} onDelete={categoryDelete} - className="flex flex-col justify-center space-y-4 p-10"/> + className="flex flex-col justify-center space-y-4"/> ); } diff --git a/src/app/entities/page.tsx b/src/app/entities/page.tsx index 8c76f29..6f41ba5 100644 --- a/src/app/entities/page.tsx +++ b/src/app/entities/page.tsx @@ -28,6 +28,6 @@ export default async function EntitiesPage() { entities={entities} onSubmit={entityCreateUpdate} onDelete={entityDelete} - className="flex flex-col justify-center space-y-4 p-10"/> + className="flex flex-col justify-center space-y-4"/> ); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cac7e3c..1cb5dcb 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -22,10 +22,10 @@ export default function RootLayout({ -
+
{children} -
+ ); diff --git a/src/app/page.tsx b/src/app/page.tsx index b217abf..54450d0 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -200,7 +200,7 @@ export default async function DashboardPage(props: { searchParams?: { scope: Sco categoryPercentages={categoryPercentages} entityExpenses={entityExpensesFormat} entityPercentages={entityPercentages} - className="flex flex-col justify-center space-y-4 p-10" + className="flex flex-col justify-center space-y-4" /> ); } diff --git a/src/app/payments/page.tsx b/src/app/payments/page.tsx index 38d123c..bbec906 100644 --- a/src/app/payments/page.tsx +++ b/src/app/payments/page.tsx @@ -58,6 +58,6 @@ export default async function PaymentsPage() { categories={categories} onSubmit={paymentCreateUpdate} onDelete={paymentDelete} - className="flex flex-col justify-center space-y-4 p-10"/> + className="flex flex-col justify-center space-y-4"/> ); } From 81c41567bcdd4346384b6ef972fd35cb1590995c Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Wed, 13 Mar 2024 22:51:53 +0100 Subject: [PATCH 02/17] N-FIN-32: reduce padding on mobile devices --- src/app/layout.tsx | 2 +- src/components/navigation.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 1cb5dcb..95bd21f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -22,7 +22,7 @@ export default function RootLayout({ -
+
{children}
diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index e6c9648..c744453 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -16,7 +16,7 @@ export default function Navigation() { return (
- +
Finances From 586182e69b3dd48f4285abbf06f54e159a54e38f Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 20:02:03 +0100 Subject: [PATCH 03/17] N-FIN-30: set currency input mode to 'numeric' --- src/components/ui/currency-input.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ui/currency-input.tsx b/src/components/ui/currency-input.tsx index 5e41c9e..acc15f3 100644 --- a/src/components/ui/currency-input.tsx +++ b/src/components/ui/currency-input.tsx @@ -53,6 +53,7 @@ export default function CurrencyInput(props: TextInputProps) { { setValue(ev.target.value); From 3454c8a03a915e1f8830c574e7ea6a2a375a3632 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 20:37:37 +0100 Subject: [PATCH 04/17] N-FIN-30: add new auto-complete component --- src/components/ui/auto-complete-input.tsx | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/components/ui/auto-complete-input.tsx diff --git a/src/components/ui/auto-complete-input.tsx b/src/components/ui/auto-complete-input.tsx new file mode 100644 index 0000000..29363e6 --- /dev/null +++ b/src/components/ui/auto-complete-input.tsx @@ -0,0 +1,100 @@ +'use client'; + +import * as React from 'react'; +import { useEffect, useState } from 'react'; +import { cn } from '@/lib/utils'; + +export interface AutoCompleteInputProps + extends React.InputHTMLAttributes { + items: { label: string, value: any }[]; + next?: React.RefObject; +} + +const AutoCompleteInput = React.forwardRef( + ({className, type, ...props}, ref) => { + + const [value, setValue] = useState(getInitialValue()); + const [open, setOpen] = useState(false); + const [lastKey, setLastKey] = useState(''); + const [filteredItems, setFilteredItems] = useState(props.items); + + function getInitialValue() { + + if (!props.items) { + return ''; + } + + const item = props.items?.find(item => item.value === props.value); + return item?.label || ''; + } + + function handleChange(e: React.ChangeEvent) { + + props.onChange?.(undefined as any); + const value = e.target.value; + + setFilteredItems(props?.items?.filter((item) => { + return item.label.toLowerCase().includes(value.toLowerCase()); + })); + + setValue(value); + setOpen(value.length > 0); + } + + useEffect(() => { + if (filteredItems.length === 1 && /^[a-zA-Z0-9]$/.test(lastKey)) { + setValue(filteredItems[0].label); + setOpen(false); + props.onChange?.({target: {value: filteredItems[0].value}} as any); + props.next && props.next.current?.focus(); + } + }, [filteredItems]); + + return ( +
+ { + if (e.metaKey || e.ctrlKey || e.altKey) { + props.onKeyDown?.(e); + return; + } + setLastKey(e.key); + props.onKeyDown?.(e); + }} + /> + { + open && ( +
+ {filteredItems?.map((item) => +
{ + props.onChange?.({target: {value: item.value}} as any); + props.next && props.next.current?.focus(); + setValue(item.label); + setOpen(false); + }} + key={item.value}> + {item.label} +
, + )} +
+ ) + } +
+ ); + }, +); +AutoCompleteInput.displayName = 'Input'; + +export { AutoCompleteInput }; From 75c1b82eff7397b3bdd44148de8cf435d5807230 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 20:39:10 +0100 Subject: [PATCH 05/17] N-FIN-30: apply new component to payment form --- src/components/form/paymentForm.tsx | 204 ++++------------------------ 1 file changed, 28 insertions(+), 176 deletions(-) diff --git a/src/components/form/paymentForm.tsx b/src/components/form/paymentForm.tsx index d6323dd..705587e 100644 --- a/src/components/form/paymentForm.tsx +++ b/src/components/form/paymentForm.tsx @@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; -import React, { useState } from 'react'; +import React, { useRef } from 'react'; import { Button } from '@/components/ui/button'; import { ActionResponse } from '@/lib/types/actionResponse'; import { useRouter } from 'next/navigation'; @@ -16,11 +16,11 @@ import { paymentFormSchema } from '@/lib/form-schemas/paymentFormSchema'; import CurrencyInput from '@/components/ui/currency-input'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { cn } from '@/lib/utils'; -import { CalendarIcon, Check, ChevronsUpDown } from 'lucide-react'; +import { CalendarIcon } from 'lucide-react'; import { format } from 'date-fns'; import { Calendar } from '@/components/ui/calendar'; -import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'; import { Textarea } from '@/components/ui/textarea'; +import { AutoCompleteInput } from '@/components/ui/auto-complete-input'; export default function PaymentForm({value, entities, categories, onSubmit, className}: { value: Payment | undefined, @@ -32,12 +32,6 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas const router = useRouter(); - const [filter, setFilter] = useState(''); - - const [payorOpen, setPayorOpen] = useState(false); - const [payeeOpen, setPayeeOpen] = useState(false); - const [categoryOpen, setCategoryOpen] = useState(false); - const form = useForm>({ resolver: zodResolver(paymentFormSchema), defaultValues: { @@ -73,6 +67,10 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas }; }) ?? []; + const payeeRef = useRef(null); + const categoryRef = useRef(null); + const noteRef = useRef(null); + return (
@@ -145,61 +143,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas render={({field}) => ( Payor - { - setPayorOpen(open); - setFilter(''); - }}> - - - - - - - setFilter(e.target.value)} - className="flex h-10 w-full rounded-md border-b border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50" - placeholder="Search..."/> - - {entitiesMapped - .filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase())) - .map((item) => ( -
{ - field.onChange(item.value); - setPayorOpen(false); - }}> - - {item.label} -
- ))} - -
-
-
+ + +
)} @@ -211,62 +161,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas render={({field}) => ( Payee - { - setPayeeOpen(open); - setFilter(''); - }}> - - - - - - - setFilter(e.target.value)} - className="flex h-10 w-full rounded-md border-b border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50" - placeholder="Search..."/> - - {entitiesMapped - .filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase())) - .map((item) => ( -
{ - field.onChange(item.value); - setPayeeOpen(false); - }} - > - - {item.label} -
- ))} - -
-
-
+ + +
)} @@ -278,62 +179,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas render={({field}) => ( Category - { - setCategoryOpen(open); - setFilter(''); - }}> - - - - - - - setFilter(e.target.value)} - className="flex h-10 w-full rounded-md border-b border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50" - placeholder="Search..."/> - - {categoriesMapped - .filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase())) - .map((item) => ( -
{ - field.onChange(item.value); - setCategoryOpen(false); - }} - > - - {item.label} -
- ))} - -
-
-
+ + +
)} From 698d4163147271932231743befaf3dad10b11665 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 21:33:55 +0100 Subject: [PATCH 06/17] N-FIN-34: add required shadcn/ui components --- package-lock.json | 13 ++++ package.json | 1 + src/components/ui/drawer.tsx | 118 +++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 src/components/ui/drawer.tsx diff --git a/package-lock.json b/package-lock.json index 7843c0b..f31cc7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "swr": "^2.2.5", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.0", "zod": "^3.22.4" }, "devDependencies": { @@ -6184,6 +6185,18 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "devOptional": true }, + "node_modules/vaul": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.0.tgz", + "integrity": "sha512-bZSySGbAHiTXmZychprnX/dE0EsSige88xtyyL3/MCRbrFotRPQZo7UdydGXZWw+CKbNOw5Ow8gwAo93/nB/Cg==", + "dependencies": { + "@radix-ui/react-dialog": "^1.0.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 2cb23d4..5262d91 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "swr": "^2.2.5", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.0", "zod": "^3.22.4" }, "devDependencies": { diff --git a/src/components/ui/drawer.tsx b/src/components/ui/drawer.tsx new file mode 100644 index 0000000..8f28ade --- /dev/null +++ b/src/components/ui/drawer.tsx @@ -0,0 +1,118 @@ +'use client'; + +import * as React from 'react'; +import { Drawer as DrawerPrimitive } from 'vaul'; + +import { cn } from '@/lib/utils'; + +const Drawer = ({ + shouldScaleBackground = true, + ...props +}: React.ComponentProps) => ( + +); +Drawer.displayName = 'Drawer'; + +const DrawerTrigger = DrawerPrimitive.Trigger; + +const DrawerPortal = DrawerPrimitive.Portal; + +const DrawerClose = DrawerPrimitive.Close; + +const DrawerOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName; + +const DrawerContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, children, ...props}, ref) => ( + + + +
+ {children} + + +)); +DrawerContent.displayName = 'DrawerContent'; + +const DrawerHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DrawerHeader.displayName = 'DrawerHeader'; + +const DrawerFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DrawerFooter.displayName = 'DrawerFooter'; + +const DrawerTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +DrawerTitle.displayName = DrawerPrimitive.Title.displayName; + +const DrawerDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +DrawerDescription.displayName = DrawerPrimitive.Description.displayName; + +export { + Drawer, + DrawerPortal, + DrawerOverlay, + DrawerTrigger, + DrawerClose, + DrawerContent, + DrawerHeader, + DrawerFooter, + DrawerTitle, + DrawerDescription, +}; From 36563db77ee9e422ed00f90adb12c20afbcceeb5 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 21:35:13 +0100 Subject: [PATCH 07/17] N-FIN-34: add new navigation variant for mobile devices --- src/components/navigation.tsx | 146 ++++++++++++++++++-------- src/components/ui/navigation-menu.tsx | 5 + 2 files changed, 108 insertions(+), 43 deletions(-) diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index c744453..f004745 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -2,65 +2,125 @@ import { NavigationMenu, + navigationMenuIconTriggerStyle, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, navigationMenuTriggerStyle, } from '@/components/ui/navigation-menu'; -import React from 'react'; +import React, { useState } from 'react'; import Link from 'next/link'; -import { User } from 'lucide-react'; +import { Banknote, Home, Menu, Tag, User, UserSearch } from 'lucide-react'; +import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer'; +import { Button } from '@/components/ui/button'; export default function Navigation() { + const [open, setOpen] = useState(false); + return (
- - -
- - Finances - - - - - Dashboard - +
+ setOpen(open)}> + + + + +
+ setOpen(false)} + passHref> + + Dashboard - - - - - Payments - + setOpen(false)} + passHref> + + Payments - - - - - Entities - + setOpen(false)} + passHref> + + Entities - - - - - Categories - + setOpen(false)} + passHref> + + Categories - -
- - - - - Account + setOpen(false)} + passHref> - - - - - + Account + +
+ + +
+
+ + +
+ + Finances + + + + + Dashboard + + + + + + + Payments + + + + + + + Entities + + + + + + + Categories + + + +
+ + + + + Account + + + + +
+
+
); } diff --git a/src/components/ui/navigation-menu.tsx b/src/components/ui/navigation-menu.tsx index 800788d..71f001a 100644 --- a/src/components/ui/navigation-menu.tsx +++ b/src/components/ui/navigation-menu.tsx @@ -44,6 +44,10 @@ const navigationMenuTriggerStyle = cva( 'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50', ); +const navigationMenuIconTriggerStyle = cva( + 'group inline-flex h-10 w-full items-center justify-start rounded-md bg-background px-4 py-2 space-x-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50', +); + const NavigationMenuTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -117,6 +121,7 @@ NavigationMenuIndicator.displayName = export { navigationMenuTriggerStyle, + navigationMenuIconTriggerStyle, NavigationMenu, NavigationMenuList, NavigationMenuItem, From 7ebc05c2570a992fa133afbfac1f15086ee68eea Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 21:36:31 +0100 Subject: [PATCH 08/17] N-FIN-34: add space between title and dashboard scope selection --- src/components/dashboardPageClientComponents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboardPageClientComponents.tsx b/src/components/dashboardPageClientComponents.tsx index 314fa5c..8f368da 100644 --- a/src/components/dashboardPageClientComponents.tsx +++ b/src/components/dashboardPageClientComponents.tsx @@ -49,7 +49,7 @@ export default function DashboardPageClientContent( return (
-
+

Dashboard

From 36817e581b265c42f8d2cb039c74195d0c64f211 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 23:52:07 +0100 Subject: [PATCH 09/17] N-FIN-31: removed unused variables --- src/components/paymentPageClientComponents.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/components/paymentPageClientComponents.tsx b/src/components/paymentPageClientComponents.tsx index 22fa031..d25f5df 100644 --- a/src/components/paymentPageClientComponents.tsx +++ b/src/components/paymentPageClientComponents.tsx @@ -100,20 +100,6 @@ export default function PaymentPageClientContent({ ); }; - const entitiesMapped = entities?.map((entity) => { - return { - label: entity.name, - value: entity.id, - }; - }) ?? []; - - const categoriesMapped = categories?.map((category) => { - return { - label: category.name, - value: category.id, - }; - }) ?? []; - return (
From 557d89898168ffa82782a9660b0bff264fa68e7a Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 23:56:03 +0100 Subject: [PATCH 10/17] N-FIN-31: apply column size to data table --- src/components/ui/data-table.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ui/data-table.tsx b/src/components/ui/data-table.tsx index c522f86..d672362 100644 --- a/src/components/ui/data-table.tsx +++ b/src/components/ui/data-table.tsx @@ -45,7 +45,8 @@ export function DataTable({ {headerGroup.headers.map((header) => { return ( - + {header.isPlaceholder ? null : flexRender( From e60561ffc086ed63b6d4469e7b6335ef84671a4b Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sat, 16 Mar 2024 23:56:17 +0100 Subject: [PATCH 11/17] N-FIN-31: set column sizes to definition --- src/app/categories/columns.tsx | 1 + src/app/entities/columns.tsx | 1 + src/app/payments/columns.tsx | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/src/app/categories/columns.tsx b/src/app/categories/columns.tsx index 196bcdd..bd8e60d 100644 --- a/src/app/categories/columns.tsx +++ b/src/app/categories/columns.tsx @@ -25,6 +25,7 @@ export const columns = ( ); }, + size: 65, }, { accessorKey: 'createdAt', diff --git a/src/app/entities/columns.tsx b/src/app/entities/columns.tsx index a56dc66..90b3754 100644 --- a/src/app/entities/columns.tsx +++ b/src/app/entities/columns.tsx @@ -17,6 +17,7 @@ export const columns = ( { accessorKey: 'type', header: 'Type', + size: 100, }, { accessorKey: 'createdAt', diff --git a/src/app/payments/columns.tsx b/src/app/payments/columns.tsx index 32a2157..d3b950e 100644 --- a/src/app/payments/columns.tsx +++ b/src/app/payments/columns.tsx @@ -18,6 +18,7 @@ export const columns = ( cell: ({row}) => { return format(row.original.date, 'PPP'); }, + size: 175, }, { accessorKey: 'amount', @@ -28,6 +29,7 @@ export const columns = ( currency: 'EUR', }).format(row.getValue('amount') as number / 100); }, + size: 70, }, { accessorKey: 'payorId', @@ -36,6 +38,7 @@ export const columns = ( const entity = entities.find((entity) => entity.id === row.original.payorId); return entity?.name ?? '-'; }, + size: 200, }, { accessorKey: 'payeeId', @@ -44,6 +47,7 @@ export const columns = ( const entity = entities.find((entity) => entity.id === row.original.payeeId); return entity?.name ?? '-'; }, + size: 200, }, { accessorKey: 'categoryId', @@ -60,10 +64,12 @@ export const columns = (
); }, + size: 200, }, { accessorKey: 'note', header: 'Note', + size: 200, }, { id: 'actions', From b064448119ecc6bbd4628a4d4da61875c09d84e2 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 00:08:00 +0100 Subject: [PATCH 12/17] N-FIN-31: fix card and button alignment --- src/app/account/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/account/page.tsx b/src/app/account/page.tsx index fae73de..4bc3d46 100644 --- a/src/app/account/page.tsx +++ b/src/app/account/page.tsx @@ -42,7 +42,7 @@ export default async function AccountPage() { return (
- + Hey, {user?.username}! This is your account overview. @@ -81,7 +81,7 @@ export default async function AccountPage() {
- + { process.env.NODE_ENV === 'development' && ( From 206ad0c528f559fd31f983f9e6abab6ee26e09cd Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 00:42:01 +0100 Subject: [PATCH 13/17] N-FIN-33: create useMediaQuery hook --- src/lib/hooks/useMediaQuery.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/lib/hooks/useMediaQuery.ts diff --git a/src/lib/hooks/useMediaQuery.ts b/src/lib/hooks/useMediaQuery.ts new file mode 100644 index 0000000..0d7a61d --- /dev/null +++ b/src/lib/hooks/useMediaQuery.ts @@ -0,0 +1,16 @@ +import { useEffect, useMemo, useState } from 'react'; + +export function useMediaQuery(mq: string) { + + const mql = useMemo(() => matchMedia(mq), [mq]); + const [matches, setMatch] = useState(mql.matches); + + useEffect(() => { + const listener = (e: any) => setMatch(e.matches); + mql.addEventListener('change', listener); + + return () => mql.removeEventListener('change', listener); + }, [mq, mql]); + + return matches; +} From ebf174e9a2ac24900084439abbc14d3b12c6d25d Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 00:42:19 +0100 Subject: [PATCH 14/17] N-FIN-33: move forms to drawers on mobile devices --- .../categoryPageClientComponents.tsx | 68 ++++++++++++----- src/components/entityPageClientComponents.tsx | 68 ++++++++++++----- .../paymentPageClientComponents.tsx | 74 +++++++++++++------ 3 files changed, 148 insertions(+), 62 deletions(-) diff --git a/src/components/categoryPageClientComponents.tsx b/src/components/categoryPageClientComponents.tsx index ac8b908..74b1ff4 100644 --- a/src/components/categoryPageClientComponents.tsx +++ b/src/components/categoryPageClientComponents.tsx @@ -23,6 +23,8 @@ import { } from '@/components/ui/alert-dialog'; import { categoryFormSchema } from '@/lib/form-schemas/categoryFormSchema'; import CategoryForm from '@/components/form/categoryForm'; +import { useMediaQuery } from '@/lib/hooks/useMediaQuery'; +import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer'; export default function CategoryPageClientContent({categories, onSubmit, onDelete, className}: { categories: Category[], @@ -31,6 +33,7 @@ export default function CategoryPageClientContent({categories, onSubmit, onDelet className: string, }) { + const isDesktop = useMediaQuery('(min-width: 768px)'); const router = useRouter(); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); @@ -97,26 +100,51 @@ export default function CategoryPageClientContent({categories, onSubmit, onDelet

Categories

{/* Edit dialog */} - - - - - - - {selectedCategory?.id ? 'Update Category' : 'Create Category'} - - - - + { + isDesktop ? ( + + + + + + + {selectedCategory?.id ? 'Update Category' : 'Create Category'} + + + + + ) : ( + + + + + + + {selectedCategory?.id ? 'Update Category' : 'Create Category'} + + + + + ) + }
{/* Data Table */} diff --git a/src/components/entityPageClientComponents.tsx b/src/components/entityPageClientComponents.tsx index 4f4a8bd..12697be 100644 --- a/src/components/entityPageClientComponents.tsx +++ b/src/components/entityPageClientComponents.tsx @@ -24,6 +24,8 @@ import { AlertDialogFooter, AlertDialogHeader, } from '@/components/ui/alert-dialog'; +import { useMediaQuery } from '@/lib/hooks/useMediaQuery'; +import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer'; export default function EntityPageClientContent({entities, onSubmit, onDelete, className}: { entities: Entity[], @@ -32,6 +34,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c className: string, }) { + const isDesktop = useMediaQuery('(min-width: 768px)'); const router = useRouter(); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); @@ -125,26 +128,51 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c

Entities

{/* Edit dialog */} - - - - - - - {selectedEntity?.id ? 'Update Entity' : 'Create Entity'} - - - - + { + isDesktop ? ( + + + + + + + {selectedEntity?.id ? 'Update Entity' : 'Create Entity'} + + + + + ) : ( + + + + + + + {selectedEntity?.id ? 'Update Entity' : 'Create Entity'} + + + + + ) + }
{/* Filter input */} diff --git a/src/components/paymentPageClientComponents.tsx b/src/components/paymentPageClientComponents.tsx index d25f5df..60a21fd 100644 --- a/src/components/paymentPageClientComponents.tsx +++ b/src/components/paymentPageClientComponents.tsx @@ -23,6 +23,8 @@ import { paymentFormSchema } from '@/lib/form-schemas/paymentFormSchema'; import { Category, Entity, Payment } from '@prisma/client'; import PaymentForm from '@/components/form/paymentForm'; import { columns } from '@/app/payments/columns'; +import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer'; +import { useMediaQuery } from '@/lib/hooks/useMediaQuery'; export default function PaymentPageClientContent({ payments, @@ -40,6 +42,7 @@ export default function PaymentPageClientContent({ className: string, }) { + const isDesktop = useMediaQuery('(min-width: 768px)'); const router = useRouter(); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); @@ -106,28 +109,55 @@ export default function PaymentPageClientContent({

Payments

{/* Edit dialog */} - - - - - - - {selectedPayment?.id ? 'Update Payment' : 'Create Payment'} - - - - + { + isDesktop ? ( + + + + + + + {selectedPayment?.id ? 'Update Payment' : 'Create Payment'} + + + + + ) : ( + + + + + + + {selectedPayment?.id ? 'Update Payment' : 'Create Payment'} + + + + + ) + }
{/* Data Table */} From f0ee68beb2515ca4b7fb8aa4f3aaced9e88360bb Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 01:22:58 +0100 Subject: [PATCH 15/17] N-FIN-33: fix button texts --- src/components/categoryPageClientComponents.tsx | 2 +- src/components/entityPageClientComponents.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/categoryPageClientComponents.tsx b/src/components/categoryPageClientComponents.tsx index 74b1ff4..f59b3f0 100644 --- a/src/components/categoryPageClientComponents.tsx +++ b/src/components/categoryPageClientComponents.tsx @@ -130,7 +130,7 @@ export default function CategoryPageClientContent({categories, onSubmit, onDelet setSelectedCategory(undefined); setIsEditDialogOpen(true); }}> - Create Payment + Create Category diff --git a/src/components/entityPageClientComponents.tsx b/src/components/entityPageClientComponents.tsx index 12697be..3845ee1 100644 --- a/src/components/entityPageClientComponents.tsx +++ b/src/components/entityPageClientComponents.tsx @@ -158,7 +158,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c setSelectedEntity(undefined); setIsEditDialogOpen(true); }}> - Create Payment + Create Entity From 34a76cf93ba3730f24c97c6451a4ab4a1893f0d5 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 01:23:21 +0100 Subject: [PATCH 16/17] N-FIN-33: fix hook accessing matchMedia while undefined --- src/lib/hooks/useMediaQuery.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/lib/hooks/useMediaQuery.ts b/src/lib/hooks/useMediaQuery.ts index 0d7a61d..9b9b3dd 100644 --- a/src/lib/hooks/useMediaQuery.ts +++ b/src/lib/hooks/useMediaQuery.ts @@ -1,16 +1,21 @@ -import { useEffect, useMemo, useState } from 'react'; +'use client'; + +import { useEffect, useState } from 'react'; export function useMediaQuery(mq: string) { - const mql = useMemo(() => matchMedia(mq), [mq]); - const [matches, setMatch] = useState(mql.matches); + const [matches, setMatch] = useState( + () => typeof window !== 'undefined' ? window.matchMedia(mq).matches : false, + ); useEffect(() => { - const listener = (e: any) => setMatch(e.matches); - mql.addEventListener('change', listener); - - return () => mql.removeEventListener('change', listener); - }, [mq, mql]); + if (typeof window !== 'undefined') { + const mql = window.matchMedia(mq); + const listener = (e: any) => setMatch(e.matches); + mql.addEventListener('change', listener); + return () => mql.removeEventListener('change', listener); + } + }, [mq]); return matches; } From 86b47db26f57f001ac6d3c776829aa9c0790a5a1 Mon Sep 17 00:00:00 2001 From: Markus Thielker Date: Sun, 17 Mar 2024 01:28:02 +0100 Subject: [PATCH 17/17] N-FIN-v1.1.0: update package.json --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f31cc7a..744cf02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "next-finances", - "version": "1.0.1", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "next-finances", - "version": "1.0.1", + "version": "1.1.0", "license": "MIT", "dependencies": { "@hookform/resolvers": "^3.3.4", diff --git a/package.json b/package.json index 5262d91..85074f6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "next-finances", "description": "A finances application to keep track of my personal spendings", "homepage": "https://github.com/MarkusThielker/next-finances", - "version": "1.0.1", + "version": "1.1.0", "license": "MIT", "author": { "name": "Markus Thielker"