1
1
"use client" ;
2
2
3
- import React from "react" ;
3
+ import React , { useState } from "react" ;
4
4
import { useForm } from "react-hook-form" ;
5
5
import { zodResolver } from "@hookform/resolvers/zod" ;
6
+ import emailjs from "@emailjs/browser" ;
6
7
8
+ import PageHeader from "@/components/UI/PageHeader.component" ;
7
9
import Button from "@/components/UI/Button.component" ;
8
10
import InputField from "@/components/UI/InputField.component" ;
9
11
import { formSchema , FormData } from "./config/formConfig" ;
10
12
11
13
interface ContactFormProps {
12
- onSubmit : ( data : FormData ) => Promise < void > ;
13
14
csrfToken ?: string ;
15
+ onSubmit ?: ( data : FormData ) => Promise < string > ;
16
+ initialResponse ?: string ;
14
17
}
15
18
16
19
/**
17
- * A simplified contact form component that directly uses the form schema
18
- * without complex generic abstractions.
20
+ * ContactForm component - A complete contact form with EmailJS integration
21
+ * Handles both the form UI and submission logic in a single, clear component
19
22
*/
20
- const ContactForm : React . FC < ContactFormProps > = ( { onSubmit, csrfToken } ) => {
23
+ const ContactForm : React . FC < ContactFormProps > = ( {
24
+ csrfToken = "" ,
25
+ onSubmit : onSubmitProp ,
26
+ initialResponse = "" ,
27
+ } ) => {
28
+ const [ serverResponse , setServerResponse ] = useState < string > ( initialResponse ) ;
29
+
21
30
const {
22
31
register,
23
32
handleSubmit,
@@ -26,63 +35,112 @@ const ContactForm: React.FC<ContactFormProps> = ({ onSubmit, csrfToken }) => {
26
35
resolver : zodResolver ( formSchema ) ,
27
36
} ) ;
28
37
38
+ /**
39
+ * Default form submission handler using EmailJS.
40
+ * @param {FormData } data - The form data.
41
+ * @return {Promise<string> } A promise that resolves to a success or error message.
42
+ */
43
+ const defaultOnSubmit = async ( data : FormData ) : Promise < string > => {
44
+ const EMAIL_API_KEY = process . env . NEXT_PUBLIC_EMAIL_API_KEY ?? "changeme" ;
45
+ const TEMPLATE_KEY =
46
+ process . env . NEXT_PUBLIC_EMAIL_TEMPLATE_KEY ?? "changeme" ;
47
+ const SERVICE_KEY = process . env . NEXT_PUBLIC_EMAIL_SERVICE_KEY ?? "changeme" ;
48
+
49
+ try {
50
+ emailjs . init ( EMAIL_API_KEY ) ;
51
+ await emailjs . send ( SERVICE_KEY , TEMPLATE_KEY , data ) ;
52
+ return "Takk for din beskjed" ;
53
+ } catch {
54
+ return "Feil under sending av skjema" ;
55
+ }
56
+ } ;
57
+
58
+ const handleFormSubmit = async ( data : FormData ) : Promise < void > => {
59
+ const submitHandler = onSubmitProp ?? defaultOnSubmit ;
60
+ const message = await submitHandler ( data ) ;
61
+ setServerResponse ( message ) ;
62
+ } ;
63
+
29
64
return (
30
- < form
31
- id = "contact-form"
32
- className = "text-center"
33
- onSubmit = { handleSubmit ( onSubmit ) }
34
- method = "POST"
35
- action = "/api/form"
36
- aria-label = "Contact Form"
37
- >
38
- { csrfToken && < input type = "hidden" name = "_csrf" value = { csrfToken } /> }
39
- < fieldset >
40
- < legend className = "text-center mx-auto text-xl mt-4 sr-only" >
41
- Kontaktskjema
42
- </ legend >
65
+ < main data-testid = "kontaktcontent" id = "maincontent" >
66
+ < div className = "mt-32 bg-graybg" >
67
+ < PageHeader > Kontakt</ PageHeader >
68
+ < div className = "px-4 lg:px-0 xl:px-0 md:px-0" >
69
+ < div className = "container mx-auto bg-slate-700 rounded-sm shadow-sm sm:mb-4" >
70
+ < div className = "p-4 mx-auto md:h-full mt-4 flex flex-col justify-center items-center min-h-[470px]" >
71
+ < div className = "p-2 md:p-6 pt-8" >
72
+ { serverResponse ? (
73
+ < h3 className = "m-2 h-32 text-xl text-center text-gray-300" >
74
+ { serverResponse }
75
+ </ h3 >
76
+ ) : (
77
+ < div className = "bg-gray-800 p-4 md:p-6 rounded-lg pt-8" >
78
+ < form
79
+ id = "contact-form"
80
+ className = "text-center"
81
+ onSubmit = { handleSubmit ( handleFormSubmit ) }
82
+ method = "POST"
83
+ action = "/api/form"
84
+ aria-label = "Contact Form"
85
+ >
86
+ { csrfToken && (
87
+ < input type = "hidden" name = "_csrf" value = { csrfToken } />
88
+ ) }
89
+ < fieldset >
90
+ < legend className = "text-center mx-auto text-xl mt-4 sr-only" >
91
+ Kontaktskjema
92
+ </ legend >
43
93
44
- < InputField < FormData >
45
- name = "navn"
46
- label = "Fullt navn"
47
- htmlFor = "navn"
48
- register = { register }
49
- error = { errors . navn ?. message }
50
- isRequired
51
- inputPattern = { / ^ [ a - z A - Z æ ø å Æ Ø Å ] + $ / }
52
- title = "Vennligst bruk norske bokstaver"
53
- />
54
- < br />
94
+ < InputField < FormData >
95
+ name = "navn"
96
+ label = "Fullt navn"
97
+ htmlFor = "navn"
98
+ register = { register }
99
+ error = { errors . navn ?. message }
100
+ isRequired
101
+ inputPattern = { / ^ [ a - z A - Z æ ø å Æ Ø Å ] + $ / }
102
+ title = "Vennligst bruk norske bokstaver"
103
+ />
104
+ < br />
55
105
56
- < InputField < FormData >
57
- name = "telefon"
58
- label = "Telefonnummer"
59
- htmlFor = "telefon"
60
- register = { register }
61
- error = { errors . telefon ?. message }
62
- isRequired
63
- inputPattern = { / ^ \d { 8 } $ / }
64
- title = "Vennligst oppgi et gyldig telefonnummer"
65
- />
66
- < br />
106
+ < InputField < FormData >
107
+ name = "telefon"
108
+ label = "Telefonnummer"
109
+ htmlFor = "telefon"
110
+ register = { register }
111
+ error = { errors . telefon ?. message }
112
+ isRequired
113
+ inputPattern = { / ^ \d { 8 } $ / }
114
+ title = "Vennligst oppgi et gyldig telefonnummer"
115
+ />
116
+ < br />
67
117
68
- < InputField < FormData >
69
- name = "tekst"
70
- label = "Hva ønsker du å si?"
71
- htmlFor = "tekst"
72
- register = { register }
73
- error = { errors . tekst ?. message }
74
- isRequired
75
- type = "textarea"
76
- />
77
- < br />
78
- </ fieldset >
118
+ < InputField < FormData >
119
+ name = "tekst"
120
+ label = "Hva ønsker du å si?"
121
+ htmlFor = "tekst"
122
+ register = { register }
123
+ error = { errors . tekst ?. message }
124
+ isRequired
125
+ type = "textarea"
126
+ />
127
+ < br />
128
+ </ fieldset >
79
129
80
- < div className = "-mt-4" >
81
- < Button disabled = { isSubmitting } data-testid = "submit-button" >
82
- Send skjema
83
- </ Button >
130
+ < div className = "-mt-4" >
131
+ < Button disabled = { isSubmitting } data-testid = "submit-button" >
132
+ Send skjema
133
+ </ Button >
134
+ </ div >
135
+ </ form >
136
+ </ div >
137
+ ) }
138
+ </ div >
139
+ </ div >
140
+ </ div >
141
+ </ div >
84
142
</ div >
85
- </ form >
143
+ </ main >
86
144
) ;
87
145
} ;
88
146
0 commit comments