diff --git a/package-lock.json b/package-lock.json
index a02d66f2..0ef25aef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -40,7 +40,8 @@
"react-i18next": "^12.1.5",
"sass": "^1.35.1",
"styled-jsx": "^5.1.0",
- "uuid": "^8.3.2"
+ "uuid": "^8.3.2",
+ "zod": "^3.22.4"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.2",
@@ -792,6 +793,36 @@
"glob": "7.1.7"
}
},
+ "node_modules/@next/swc-android-arm-eabi": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.4.tgz",
+ "integrity": "sha512-DWlalTSkLjDU11MY11jg17O1gGQzpRccM9Oes2yTqj2DpHndajrXHGxj9HGtJ+idq2k7ImUdJVWS2h2l/EDJOw==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-android-arm64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.4.tgz",
+ "integrity": "sha512-sRavmUImUCf332Gy+PjIfLkMhiRX1Ez4SI+3vFDRs1N5eXp+uNzjFUK/oLMMOzk6KFSkbiK/3Wt8+dHQR/flNg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@next/swc-darwin-arm64": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.4.tgz",
@@ -807,6 +838,156 @@
"node": ">= 10"
}
},
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.4.tgz",
+ "integrity": "sha512-a6LBuoYGcFOPGd4o8TPo7wmv5FnMr+Prz+vYHopEDuhDoMSHOnC+v+Ab4D7F0NMZkvQjEJQdJS3rqgFhlZmKlw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-freebsd-x64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.4.tgz",
+ "integrity": "sha512-kkbzKVZGPaXRBPisoAQkh3xh22r+TD+5HwoC5bOkALraJ0dsOQgSMAvzMXKsN3tMzJUPS0tjtRf1cTzrQ0I5vQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm-gnueabihf": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.4.tgz",
+ "integrity": "sha512-7qA1++UY0fjprqtjBZaOA6cas/7GekpjVsZn/0uHvquuITFCdKGFCsKNBx3S0Rpxmx6WYo0GcmhNRM9ru08BGg==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.4.tgz",
+ "integrity": "sha512-xzYZdAeq883MwXgcwc72hqo/F/dwUxCukpDOkx/j1HTq/J0wJthMGjinN9wH5bPR98Mfeh1MZJ91WWPnZOedOg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.4.tgz",
+ "integrity": "sha512-8rXr3WfmqSiYkb71qzuDP6I6R2T2tpkmf83elDN8z783N9nvTJf2E7eLx86wu2OJCi4T05nuxCsh4IOU3LQ5xw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.4.tgz",
+ "integrity": "sha512-Ngxh51zGSlYJ4EfpKG4LI6WfquulNdtmHg1yuOYlaAr33KyPJp4HeN/tivBnAHcZkoNy0hh/SbwDyCnz5PFJQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.4.tgz",
+ "integrity": "sha512-gOvwIYoSxd+j14LOcvJr+ekd9fwYT1RyMAHOp7znA10+l40wkFiMONPLWiZuHxfRk+Dy7YdNdDh3ImumvL6VwA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.4.tgz",
+ "integrity": "sha512-q3NJzcfClgBm4HvdcnoEncmztxrA5GXqKeiZ/hADvC56pwNALt3ngDC6t6qr1YW9V/EPDxCYeaX4zYxHciW4Dw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-ia32-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.4.tgz",
+ "integrity": "sha512-/eZ5ncmHUYtD2fc6EUmAIZlAJnVT2YmxDsKs1Ourx0ttTtvtma/WKlMV5NoUsyOez0f9ExLyOpeCoz5aj+MPXw==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.4.tgz",
+ "integrity": "sha512-0MffFmyv7tBLlji01qc0IaPP/LVExzvj7/R5x1Jph1bTAIj4Vu81yFQWHHQAP6r4ff9Ukj1mBK6MDNVXm7Tcvw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -8022,6 +8203,14 @@
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
+ },
+ "node_modules/zod": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
+ "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
},
"dependencies": {
@@ -8511,12 +8700,84 @@
"glob": "7.1.7"
}
},
+ "@next/swc-android-arm-eabi": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.4.tgz",
+ "integrity": "sha512-DWlalTSkLjDU11MY11jg17O1gGQzpRccM9Oes2yTqj2DpHndajrXHGxj9HGtJ+idq2k7ImUdJVWS2h2l/EDJOw==",
+ "optional": true
+ },
+ "@next/swc-android-arm64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.4.tgz",
+ "integrity": "sha512-sRavmUImUCf332Gy+PjIfLkMhiRX1Ez4SI+3vFDRs1N5eXp+uNzjFUK/oLMMOzk6KFSkbiK/3Wt8+dHQR/flNg==",
+ "optional": true
+ },
"@next/swc-darwin-arm64": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.4.tgz",
"integrity": "sha512-S6vBl+OrInP47TM3LlYx65betocKUUlTZDDKzTiRDbsRESeyIkBtZ6Qi5uT2zQs4imqllJznVjFd1bXLx3Aa6A==",
"optional": true
},
+ "@next/swc-darwin-x64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.4.tgz",
+ "integrity": "sha512-a6LBuoYGcFOPGd4o8TPo7wmv5FnMr+Prz+vYHopEDuhDoMSHOnC+v+Ab4D7F0NMZkvQjEJQdJS3rqgFhlZmKlw==",
+ "optional": true
+ },
+ "@next/swc-freebsd-x64": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.4.tgz",
+ "integrity": "sha512-kkbzKVZGPaXRBPisoAQkh3xh22r+TD+5HwoC5bOkALraJ0dsOQgSMAvzMXKsN3tMzJUPS0tjtRf1cTzrQ0I5vQ==",
+ "optional": true
+ },
+ "@next/swc-linux-arm-gnueabihf": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.4.tgz",
+ "integrity": "sha512-7qA1++UY0fjprqtjBZaOA6cas/7GekpjVsZn/0uHvquuITFCdKGFCsKNBx3S0Rpxmx6WYo0GcmhNRM9ru08BGg==",
+ "optional": true
+ },
+ "@next/swc-linux-arm64-gnu": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.4.tgz",
+ "integrity": "sha512-xzYZdAeq883MwXgcwc72hqo/F/dwUxCukpDOkx/j1HTq/J0wJthMGjinN9wH5bPR98Mfeh1MZJ91WWPnZOedOg==",
+ "optional": true
+ },
+ "@next/swc-linux-arm64-musl": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.4.tgz",
+ "integrity": "sha512-8rXr3WfmqSiYkb71qzuDP6I6R2T2tpkmf83elDN8z783N9nvTJf2E7eLx86wu2OJCi4T05nuxCsh4IOU3LQ5xw==",
+ "optional": true
+ },
+ "@next/swc-linux-x64-gnu": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.4.tgz",
+ "integrity": "sha512-Ngxh51zGSlYJ4EfpKG4LI6WfquulNdtmHg1yuOYlaAr33KyPJp4HeN/tivBnAHcZkoNy0hh/SbwDyCnz5PFJQQ==",
+ "optional": true
+ },
+ "@next/swc-linux-x64-musl": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.4.tgz",
+ "integrity": "sha512-gOvwIYoSxd+j14LOcvJr+ekd9fwYT1RyMAHOp7znA10+l40wkFiMONPLWiZuHxfRk+Dy7YdNdDh3ImumvL6VwA==",
+ "optional": true
+ },
+ "@next/swc-win32-arm64-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.4.tgz",
+ "integrity": "sha512-q3NJzcfClgBm4HvdcnoEncmztxrA5GXqKeiZ/hADvC56pwNALt3ngDC6t6qr1YW9V/EPDxCYeaX4zYxHciW4Dw==",
+ "optional": true
+ },
+ "@next/swc-win32-ia32-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.4.tgz",
+ "integrity": "sha512-/eZ5ncmHUYtD2fc6EUmAIZlAJnVT2YmxDsKs1Ourx0ttTtvtma/WKlMV5NoUsyOez0f9ExLyOpeCoz5aj+MPXw==",
+ "optional": true
+ },
+ "@next/swc-win32-x64-msvc": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.4.tgz",
+ "integrity": "sha512-0MffFmyv7tBLlji01qc0IaPP/LVExzvj7/R5x1Jph1bTAIj4Vu81yFQWHHQAP6r4ff9Ukj1mBK6MDNVXm7Tcvw==",
+ "optional": true
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -13859,6 +14120,11 @@
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
+ },
+ "zod": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
+ "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="
}
}
}
diff --git a/package.json b/package.json
index de51f16f..2dc58fe0 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,8 @@
"react-i18next": "^12.1.5",
"sass": "^1.35.1",
"styled-jsx": "^5.1.0",
- "uuid": "^8.3.2"
+ "uuid": "^8.3.2",
+ "zod": "^3.22.4"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.2",
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index def2e6c0..263fbf8e 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -208,5 +208,6 @@
"loading": "Loading...",
"topProject": "Top Project",
"top_project_standards_fulfilled": "The project inspection revealed that this project fulfilled at least 12 of the 19 Top Project <2>standards.2>",
- "standardsLink": "https://www.plant-for-the-planet.org/standards/"
+ "standardsLink": "https://www.plant-for-the-planet.org/standards/",
+ "enterValidEmail": "Please enter a valid email"
}
\ No newline at end of file
diff --git a/src/Donations/Components/ContactsForm.tsx b/src/Donations/Components/ContactsForm.tsx
index 7f07ca7a..6dbe254c 100644
--- a/src/Donations/Components/ContactsForm.tsx
+++ b/src/Donations/Components/ContactsForm.tsx
@@ -18,6 +18,7 @@ import { ContactDetails } from "@planet-sdk/common";
import { AddressCandidate, GeocodeSuggestion } from "src/Common/Types/arcgis";
import GiftIcon from "public/assets/icons/GiftIcon";
import { euCountries } from "src/Utils/countryUtils";
+import { isEmailValid } from "src/Utils/isEmailValid";
interface FormData extends ContactDetails {
isPackageWanted: boolean;
@@ -39,7 +40,7 @@ function ContactsForm(): ReactElement {
client_id: process.env.ESRI_CLIENT_ID,
client_secret: process.env.ESRI_CLIENT_SECRET,
}
- : {},
+ : {}
);
const {
profile,
@@ -62,7 +63,10 @@ function ContactsForm(): ReactElement {
React.useEffect(() => {
if (contactDetails) {
- reset({ ...contactDetails, isPackageWanted: isPackageWanted !== false && isEligibleForPackage });
+ reset({
+ ...contactDetails,
+ isPackageWanted: isPackageWanted !== false && isEligibleForPackage,
+ });
if (contactDetails.companyname) {
setIsCompany(true);
}
@@ -83,7 +87,7 @@ function ContactsForm(): ReactElement {
React.useEffect(() => {
const fiteredCountry = COUNTRY_ADDRESS_POSTALS.filter(
- (country) => country.abbrev === contactDetails.country,
+ (country) => country.abbrev === contactDetails.country
);
setPostalRegex(fiteredCountry[0]?.postal);
}, [contactDetails.country]);
@@ -95,7 +99,7 @@ function ContactsForm(): ReactElement {
query: { ...router.query, step: PAYMENT },
},
undefined,
- { shallow: true },
+ { shallow: true }
);
setContactDetails({
...enteredContactDetails,
@@ -108,8 +112,8 @@ function ContactsForm(): ReactElement {
const [postalRegex, setPostalRegex] = React.useState(
COUNTRY_ADDRESS_POSTALS.filter(
- (country) => country.abbrev === contactDetails.country,
- )[0]?.postal,
+ (country) => country.abbrev === contactDetails.country
+ )[0]?.postal
);
const changeCountry = (country: string) => {
@@ -201,7 +205,7 @@ function ContactsForm(): ReactElement {
query: { ...router.query, step: DONATE },
},
undefined,
- { shallow: true },
+ { shallow: true }
);
}}
style={{ marginRight: "12px" }}
@@ -275,9 +279,14 @@ function ContactsForm(): ReactElement {
name="email"
control={control}
rules={{
- required: true,
- pattern:
- /^([a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)$/i,
+ required: {
+ value: true,
+ message: t("emailRequired"),
+ },
+ validate: {
+ emailInvalid: (value) =>
+ value.length === 0 || isEmailValid(value),
+ },
}}
render={({ field: { onChange, value } }) => (