Merged in contact-us-form (pull request #5)

Contact us form

Approved-by: Tiago Ribeiro
This commit is contained in:
João Ramos
2024-02-13 00:51:19 +00:00
committed by Tiago Ribeiro
8 changed files with 244 additions and 9 deletions

View File

@@ -16,11 +16,13 @@
"axios": "^1.5.1",
"clsx": "^2.0.0",
"currency-symbol-map": "^5.1.0",
"daisyui": "^4.6.3",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"next": "13.5.4",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.50.1",
"react-icons": "^4.11.0",
"react-string-replace": "^1.1.1",
"sharp": "^0.32.6"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -1,6 +1,5 @@
import About from "@/templates/About";
import ComingSoon from "@/templates/ComingSoon";
import ContactUs from "@/templates/ContactUs";
export default function Page() {
return <ComingSoon page="/contact" language="ar" />;
return <ContactUs page="/contact" language="ar" />;
}

View File

@@ -1,6 +1,5 @@
import About from "@/templates/About";
import ComingSoon from "@/templates/ComingSoon";
import ContactUs from "@/templates/ContactUs";
export default function Page() {
return <ComingSoon page="/contact" language="en" />;
return <ContactUs page="/contact" language="en" />;
}

149
src/templates/ContactUs.tsx Normal file
View File

@@ -0,0 +1,149 @@
"use client";
import React from "react";
import {useForm, SubmitHandler, Controller} from "react-hook-form";
import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import Title from "@/components/Title";
import translation from "@/translation/contactus.json";
import Image from "next/image";
type FormValues = {
name: string;
email: string;
description: string;
subject: string;
type: "feedback" | "bug" | "help" | "";
};
interface Props {
language: "en" | "ar";
page: string;
}
const ErrorMessage = ({message}: {message: string}) => (
<div className="w-full">
<span className="text-mti-red">{message}</span>
</div>
);
export default function App({language, page}: Props) {
const selectOptions = [
{
label: translation.feedback[language],
value: "feedback",
},
{
label: translation.bug[language],
value: "bug",
},
{
label: translation.help[language],
value: "help",
},
];
const {register, control, handleSubmit, formState} = useForm<FormValues>({
defaultValues: {
name: "",
email: "",
description: "",
subject: "",
type: "",
},
});
const {errors, isDirty, isValid} = formState;
console.log("formState", formState.isSubmitSuccessful);
const onSubmit: SubmitHandler<FormValues> = async (data) => {
try {
const response = await fetch(`https://platform.encoach.com/api/tickets`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
reporter: {
name: data.name,
email: data.email,
},
subject: data.subject,
type: data.type,
reportedFrom: window.location.href,
status: "submitted",
date: new Date().toISOString(),
description: data.description,
}),
});
if (response.status === 200) {
const data = await response.json();
// Pass data to the page via props
console.log(data);
return;
}
} catch (err) {}
};
return (
<main className="text-mti-black flex h-screen w-full flex-col bg-white" dir={language === "ar" ? "rtl" : "ltr"}>
<Navbar currentPage={page} language={language} />
<section className="w-full bg-mti-purple text-white text-center p-8 md:p-16">
<div className="w-full h-full flex flex-col items-center justify-center">
<Title>{translation.title[language]}</Title>
</div>
</section>
<section className="w-full bg-white text-center p-8 md:p-16 flex justify-center items-center gap-32">
<form onSubmit={handleSubmit(onSubmit)} className="form-control items-center gap-2 text-mti-black flex flex-col w-96">
<input
id="name"
type="text"
placeholder={translation.name[language]}
{...register("name", {required: true})}
className="input input-bordered md:w-full sm:w-1/2 max-w-md"
/>
{errors.name && errors.name.type === "required" && <ErrorMessage message={translation.fieldRequired[language]} />}
<input
id="email"
placeholder={translation.email[language]}
type="text"
{...register("email", {required: true, pattern: /^\S+@\S+$/i})}
className="input input-bordered md:w-full sm:w-1/2 max-w-md"
/>
{errors.email && errors.email.type === "required" && <ErrorMessage message={translation.fieldRequired[language]} />}
{errors.email && errors.email.type === "pattern" && <ErrorMessage message={translation.invalidEmail[language]} />}
<input
id="subject"
placeholder={translation.subject[language]}
type="text"
{...register("subject", {required: true})}
className="input input-bordered md:w-full sm:w-1/2 max-w-md"
/>
{errors.subject && errors.subject.type === "required" && <ErrorMessage message={translation.fieldRequired[language]} />}
<select id="type" {...register("type", {required: true})} className="select select-bordered md:w-full sm:w-1/2 max-w-md">
<option value="" disabled>
{translation.selectType[language]}
</option>
{selectOptions.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
{errors.type && errors.type.type === "required" && <ErrorMessage message={translation.fieldRequired[language]} />}
<textarea
id="description"
placeholder={translation.description[language]}
{...register("description", {required: true})}
className="textarea textarea-bordered md:w-full sm:w-1/2 max-w-md"
rows={5}
/>
{errors.description && errors.description.type === "required" && <ErrorMessage message={translation.fieldRequired[language]} />}
<input type="submit" className="btn" disabled={!isDirty || !isValid} value={translation.submit[language]} />
</form>
<div className="flex flex-col">
<Image src="/person_laptop_focus.jpg" alt="Contact Us" width={500} height={340} className="rounded-xl" />
</div>
</section>
<Footer language={language} />
</main>
);
}

View File

@@ -0,0 +1,50 @@
{
"title": {
"en": "Submit a ticket",
"ar": "تقديم ملاحظة / مشكلة "
},
"name": {
"en": "Name",
"ar": "الإسم"
},
"email": {
"en": "Email",
"ar": "البريد الإلكتروني"
},
"subject": {
"en": "Subject",
"ar": "الموضوع"
},
"submit": {
"en": "Submit",
"ar": "أرسل"
},
"selectType": {
"en": "Select Type",
"ar": "أختر النوع"
},
"description": {
"en": "Description",
"ar": "الوصف"
},
"feedback": {
"en": "Feedback",
"ar": "تغذية راجعة"
},
"bug": {
"en": "Bug",
"ar": "بلاغ عن مشكلة"
},
"help": {
"en": "Help",
"ar": "طلب مساعدة"
},
"fieldRequired": {
"en": "This field is required",
"ar": "هذا الحقل إلزامي"
},
"invalidEmail": {
"en": "Invalid email",
"ar": "بريد إلكتروني خطأ"
}
}

View File

@@ -76,6 +76,9 @@ const config: Config = {
},
},
},
plugins: [],
plugins: [require("daisyui")],
daisyui: {
themes: ["light"],
}
};
export default config;

View File

@@ -677,6 +677,14 @@ cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"
css-selector-tokenizer@^0.8:
version "0.8.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz#88267ef6238e64f2215ea2764b3e2cf498b845dd"
integrity sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==
dependencies:
cssesc "^3.0.0"
fastparse "^1.1.2"
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@@ -687,11 +695,26 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
culori@^3:
version "3.3.0"
resolved "https://registry.yarnpkg.com/culori/-/culori-3.3.0.tgz#e33530adbd124d53bd6550394397e695eaaed739"
integrity sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==
currency-symbol-map@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/currency-symbol-map/-/currency-symbol-map-5.1.0.tgz#59531fbe977ba95e8d358e90e3c9e9053efb75ad"
integrity sha512-LO/lzYRw134LMDVnLyAf1dHE5tyO6axEFkR3TXjQIOmMkAM9YL6QsiUwuXzZAmFnuDJcs4hayOgyIYtViXFrLw==
daisyui@^4.6.3:
version "4.6.3"
resolved "https://registry.yarnpkg.com/daisyui/-/daisyui-4.6.3.tgz#440a87305e2e7ca1b03498bba262481961cfad4c"
integrity sha512-0Y8G0EwO1aQlvhasDuUAYH35XCK/808dwYdkT4VqQ2kqtErcd/MFaHqK4CGhXwf6PWsWImmIpotFehWkUrlxnw==
dependencies:
css-selector-tokenizer "^0.8"
culori "^3"
picocolors "^1"
postcss-js "^4"
damerau-levenshtein@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -1158,6 +1181,11 @@ fast-levenshtein@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fastparse@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
fastq@^1.6.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
@@ -2074,7 +2102,7 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
picocolors@^1.0.0:
picocolors@^1, picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
@@ -2103,7 +2131,7 @@ postcss-import@^15.1.0:
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-js@^4.0.1:
postcss-js@^4, postcss-js@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
@@ -2225,6 +2253,11 @@ react-dom@^18:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-hook-form@^7.50.1:
version "7.50.1"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.50.1.tgz#f6aeb17a863327e5a0252de8b35b4fc8990377ed"
integrity sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==
react-icons@^4.11.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65"