1
+ 'use client' ;
2
+
1
3
import { CustomerField } from '@/app/lib/definitions' ;
2
4
import Link from 'next/link' ;
3
5
import {
@@ -8,10 +10,14 @@ import {
8
10
} from '@heroicons/react/24/outline' ;
9
11
import { Button } from '@/app/ui/button' ;
10
12
import { createInvoice } from '@/app/lib/actions' ;
13
+ import { useFormState } from 'react-dom' ;
11
14
12
15
export default function Form ( { customers } : { customers : CustomerField [ ] } ) {
16
+ const initialState = { message : null , errors : { } } ;
17
+ const [ state , dispatch ] = useFormState ( createInvoice , initialState ) ;
18
+ console . log ( 'state' , state ) ;
13
19
return (
14
- < form action = { createInvoice } >
20
+ < form action = { dispatch } >
15
21
< div className = "rounded-md bg-gray-50 p-4 md:p-6" >
16
22
{ /* Customer Name */ }
17
23
< div className = "mb-4" >
@@ -24,6 +30,7 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
24
30
name = "customerId"
25
31
className = "peer block w-full cursor-pointer rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
26
32
defaultValue = ""
33
+ aria-describedby = "customer-error"
27
34
>
28
35
< option value = "" disabled >
29
36
Select a customer
@@ -36,6 +43,14 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
36
43
</ select >
37
44
< UserCircleIcon className = "pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500" />
38
45
</ div >
46
+ < div id = "customer-error" aria-live = "polite" aria-atomic = "true" >
47
+ { state . errors ?. customerId &&
48
+ state . errors . customerId . map ( ( error : string ) => (
49
+ < p className = "mt-2 text-sm text-red-500" key = { error } >
50
+ { error }
51
+ </ p >
52
+ ) ) }
53
+ </ div >
39
54
</ div >
40
55
41
56
{ /* Invoice Amount */ }
@@ -52,10 +67,19 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
52
67
step = "0.01"
53
68
placeholder = "Enter USD amount"
54
69
className = "peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
70
+ aria-describedby = "amount-error"
55
71
/>
56
72
< CurrencyDollarIcon className = "pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
57
73
</ div >
58
74
</ div >
75
+ < div id = "amount-error" aria-live = "polite" aria-atomic = "true" >
76
+ { state . errors ?. amount &&
77
+ state . errors . amount . map ( ( error : string ) => (
78
+ < p className = "mt-2 text-sm text-red-500" key = { error } >
79
+ { error }
80
+ </ p >
81
+ ) ) }
82
+ </ div >
59
83
</ div >
60
84
61
85
{ /* Invoice Status */ }
@@ -72,6 +96,7 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
72
96
type = "radio"
73
97
value = "pending"
74
98
className = "h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
99
+ aria-describedby = "status-error"
75
100
/>
76
101
< label
77
102
htmlFor = "pending"
@@ -87,6 +112,7 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
87
112
type = "radio"
88
113
value = "paid"
89
114
className = "h-4 w-4 cursor-pointer border-gray-300 bg-gray-100 text-gray-600 focus:ring-2"
115
+ aria-describedby = "status-error"
90
116
/>
91
117
< label
92
118
htmlFor = "paid"
@@ -97,7 +123,20 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
97
123
</ div >
98
124
</ div >
99
125
</ div >
126
+ < div id = "status-error" aria-live = "polite" aria-atomic = "true" >
127
+ { state . errors ?. status &&
128
+ state . errors . status . map ( ( error : string ) => (
129
+ < p className = "mt-2 text-sm text-red-500" key = { error } >
130
+ { error }
131
+ </ p >
132
+ ) ) }
133
+ </ div >
100
134
</ fieldset >
135
+ < div aria-live = "polite" aria-atomic = "true" >
136
+ { state . message && (
137
+ < p className = "mt-2 text-sm text-red-500" > { state . message } </ p >
138
+ ) }
139
+ </ div >
101
140
</ div >
102
141
< div className = "mt-6 flex justify-end gap-4" >
103
142
< Link
0 commit comments