mirror of
https://codeberg.org/MarkusThielker/finances.git
synced 2025-04-12 05:08:43 +00:00
N-FIN-30: apply new component to payment form
This commit is contained in:
parent
3454c8a03a
commit
75c1b82eff
1 changed files with 28 additions and 176 deletions
|
@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
|
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import React, { useState } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ActionResponse } from '@/lib/types/actionResponse';
|
import { ActionResponse } from '@/lib/types/actionResponse';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
@ -16,11 +16,11 @@ import { paymentFormSchema } from '@/lib/form-schemas/paymentFormSchema';
|
||||||
import CurrencyInput from '@/components/ui/currency-input';
|
import CurrencyInput from '@/components/ui/currency-input';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { CalendarIcon, Check, ChevronsUpDown } from 'lucide-react';
|
import { CalendarIcon } from 'lucide-react';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { Calendar } from '@/components/ui/calendar';
|
import { Calendar } from '@/components/ui/calendar';
|
||||||
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import { AutoCompleteInput } from '@/components/ui/auto-complete-input';
|
||||||
|
|
||||||
export default function PaymentForm({value, entities, categories, onSubmit, className}: {
|
export default function PaymentForm({value, entities, categories, onSubmit, className}: {
|
||||||
value: Payment | undefined,
|
value: Payment | undefined,
|
||||||
|
@ -32,12 +32,6 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [filter, setFilter] = useState<string>('');
|
|
||||||
|
|
||||||
const [payorOpen, setPayorOpen] = useState(false);
|
|
||||||
const [payeeOpen, setPayeeOpen] = useState(false);
|
|
||||||
const [categoryOpen, setCategoryOpen] = useState(false);
|
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof paymentFormSchema>>({
|
const form = useForm<z.infer<typeof paymentFormSchema>>({
|
||||||
resolver: zodResolver(paymentFormSchema),
|
resolver: zodResolver(paymentFormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
@ -73,6 +67,10 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas
|
||||||
};
|
};
|
||||||
}) ?? [];
|
}) ?? [];
|
||||||
|
|
||||||
|
const payeeRef = useRef<HTMLInputElement>(null);
|
||||||
|
const categoryRef = useRef<HTMLInputElement>(null);
|
||||||
|
const noteRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form autoComplete="off" onSubmit={form.handleSubmit(handleSubmit)}>
|
<form autoComplete="off" onSubmit={form.handleSubmit(handleSubmit)}>
|
||||||
|
@ -145,61 +143,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Payor</FormLabel>
|
<FormLabel>Payor</FormLabel>
|
||||||
<Popover open={payorOpen} onOpenChange={(open) => {
|
<FormControl>
|
||||||
setPayorOpen(open);
|
<AutoCompleteInput
|
||||||
setFilter('');
|
placeholder="Select payor"
|
||||||
}}>
|
items={entitiesMapped}
|
||||||
<PopoverTrigger asChild>
|
next={payeeRef}
|
||||||
<FormControl>
|
{...field} />
|
||||||
<Button
|
</FormControl>
|
||||||
variant="outline"
|
|
||||||
role="combobox"
|
|
||||||
className={cn(
|
|
||||||
'w-full justify-between',
|
|
||||||
!field.value && 'text-muted-foreground',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{field.value
|
|
||||||
? entitiesMapped.find(
|
|
||||||
(item) => item.value === field.value,
|
|
||||||
)?.label
|
|
||||||
: 'Select entity'}
|
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50"/>
|
|
||||||
</Button>
|
|
||||||
</FormControl>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-[225px] p-0">
|
|
||||||
<input
|
|
||||||
value={filter}
|
|
||||||
onChange={(e) => 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..."/>
|
|
||||||
<ScrollArea className="h-64">
|
|
||||||
{entitiesMapped
|
|
||||||
.filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase()))
|
|
||||||
.map((item) => (
|
|
||||||
<div
|
|
||||||
className="relative flex cursor-pointer hover:bg-white/10 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
||||||
key={item.value}
|
|
||||||
onClick={() => {
|
|
||||||
field.onChange(item.value);
|
|
||||||
setPayorOpen(false);
|
|
||||||
}}>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
'mr-2 h-4 w-4',
|
|
||||||
item.value === field.value
|
|
||||||
? 'opacity-100'
|
|
||||||
: 'opacity-0',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{item.label}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<ScrollBar orientation="vertical"/>
|
|
||||||
</ScrollArea>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -211,62 +161,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Payee</FormLabel>
|
<FormLabel>Payee</FormLabel>
|
||||||
<Popover open={payeeOpen} onOpenChange={(open) => {
|
<FormControl ref={payeeRef}>
|
||||||
setPayeeOpen(open);
|
<AutoCompleteInput
|
||||||
setFilter('');
|
placeholder="Select payee"
|
||||||
}}>
|
items={entitiesMapped}
|
||||||
<PopoverTrigger asChild>
|
next={categoryRef}
|
||||||
<FormControl>
|
{...field} />
|
||||||
<Button
|
</FormControl>
|
||||||
variant="outline"
|
|
||||||
role="combobox"
|
|
||||||
className={cn(
|
|
||||||
'w-full justify-between',
|
|
||||||
!field.value && 'text-muted-foreground',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{field.value
|
|
||||||
? entitiesMapped.find(
|
|
||||||
(item) => item.value === field.value,
|
|
||||||
)?.label
|
|
||||||
: 'Select entity'}
|
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50"/>
|
|
||||||
</Button>
|
|
||||||
</FormControl>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-[225px] p-0">
|
|
||||||
<input
|
|
||||||
value={filter}
|
|
||||||
onChange={(e) => 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..."/>
|
|
||||||
<ScrollArea className="h-40">
|
|
||||||
{entitiesMapped
|
|
||||||
.filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase()))
|
|
||||||
.map((item) => (
|
|
||||||
<div
|
|
||||||
className="relative flex cursor-pointer hover:bg-white/10 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
||||||
key={item.value}
|
|
||||||
onClick={() => {
|
|
||||||
field.onChange(item.value);
|
|
||||||
setPayeeOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
'mr-2 h-4 w-4',
|
|
||||||
item.value === field.value
|
|
||||||
? 'opacity-100'
|
|
||||||
: 'opacity-0',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{item.label}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<ScrollBar orientation="vertical"/>
|
|
||||||
</ScrollArea>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -278,62 +179,13 @@ export default function PaymentForm({value, entities, categories, onSubmit, clas
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Category</FormLabel>
|
<FormLabel>Category</FormLabel>
|
||||||
<Popover open={categoryOpen} onOpenChange={(open) => {
|
<FormControl ref={categoryRef}>
|
||||||
setCategoryOpen(open);
|
<AutoCompleteInput
|
||||||
setFilter('');
|
placeholder="Select category"
|
||||||
}}>
|
items={categoriesMapped}
|
||||||
<PopoverTrigger asChild>
|
next={noteRef}
|
||||||
<FormControl>
|
{...field} />
|
||||||
<Button
|
</FormControl>
|
||||||
variant="outline"
|
|
||||||
role="combobox"
|
|
||||||
className={cn(
|
|
||||||
'w-full justify-between',
|
|
||||||
!field.value && 'text-muted-foreground',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{field.value
|
|
||||||
? categoriesMapped.find(
|
|
||||||
(item) => item.value === field.value,
|
|
||||||
)?.label
|
|
||||||
: 'Select entity'}
|
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50"/>
|
|
||||||
</Button>
|
|
||||||
</FormControl>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-[225px] p-0">
|
|
||||||
<input
|
|
||||||
value={filter}
|
|
||||||
onChange={(e) => 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..."/>
|
|
||||||
<ScrollArea className="h-40">
|
|
||||||
{categoriesMapped
|
|
||||||
.filter((entity) => entity.label.toLowerCase().includes(filter.toLowerCase()))
|
|
||||||
.map((item) => (
|
|
||||||
<div
|
|
||||||
className="relative flex cursor-pointer hover:bg-white/10 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
||||||
key={item.value}
|
|
||||||
onClick={() => {
|
|
||||||
field.onChange(item.value);
|
|
||||||
setCategoryOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
'mr-2 h-4 w-4',
|
|
||||||
item.value === field.value
|
|
||||||
? 'opacity-100'
|
|
||||||
: 'opacity-0',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{item.label}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<ScrollBar orientation="vertical"/>
|
|
||||||
</ScrollArea>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Add table
Reference in a new issue