Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt contact forms to new API #30

Merged
merged 1 commit into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_API_URL=
3 changes: 3 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ on:
push:
branches: [main]

env:
VITE_API_URL: ${{ vars.API_URL }}

jobs:
build:
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ with [Vue.js](https://vuejs.org).

## 🚀 Project Setup

Copy `.env.example` to `.env`

```sh
npm install
```
Expand Down
42 changes: 30 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"dependencies": {
"@fontsource-variable/mulish": "^5.1.0",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
"altcha": "^1.0.6",
"vue": "^3.5.6",
"vue-router": "^4.4.5"
},
Expand Down
148 changes: 25 additions & 123 deletions src/components/company/CaseStudyForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,43 @@
<Fieldset>
<Textfield
id="lastname"
v-model="lastname"
name="lastname"
label="Nom :"
autocomplete="family-name"
/>
<Textfield
id="firstname"
v-model="firstname"
name="firstname"
label="Prénom :"
autocomplete="given-name"
/>
</Fieldset>

<Textfield
id="company"
v-model="company"
name="company"
label="Organisation :"
autocomplete="organization"
/>
<Textfield
id="role"
v-model="role"
name="role"
label="Rôle :"
autocomplete="organization-title"
/>

<Fieldset>
<Textfield
id="email"
v-model="email"
name="email"
type="email"
label="E-mail * :"
required
autocomplete="email"
/>
<Textfield
id="phone"
v-model="phone"
name="phone"
type="tel"
label="Téléphone :"
autocomplete="tel"
Expand All @@ -49,16 +49,10 @@
<Textfield
id="message"
type="textarea"
v-model="message"
name="message"
label="Votre besoin :"
/>

<vue-hcaptcha
@verify="getCaptcha"
sitekey="359a430d-a0bf-4548-a583-959e93110b6d"
aria-label="Rendez vous sur https://www.hcaptcha.com/accessibility pour obtenir un passe-droit accessible"
/>

<div class="form-submit">
<div class="error-message" v-if="error" aria-live="assertive">
{{ error }}
Expand All @@ -79,133 +73,41 @@
aria-label="Soumettez le formulaire"
/>
</div>

<altcha-widget
:challengeurl="captchaChallengeUrl"
name="captcha"
spamfilter
floating
/>
</form>
</template>

<script setup lang="ts">
import { ref } from "vue";
import VueHcaptcha from "@hcaptcha/vue3-hcaptcha";
import AppButton from "@/components/shared/AppButton.vue";
import { post } from "@/util/fetch";
import Textfield from "@/components/shared/form/AppTextfield.vue";
import Fieldset from "@/components/shared/form/AppFieldset.vue";
import Textfield from "@/components/shared/form/AppTextfield.vue";
import { captchaChallengeUrl, post } from "@/util/fetch";
import { extractFormData, validatePhone } from "@/util/form";
import { ref } from "vue";

/**
* Validates an email address to ensure it is not empty and follows a valid email format.
*
* @returns {boolean} True if the email is valid, false otherwise.
*/
const validateEmail = () => {
/**
* Regular expression to validate an email address:
* - It allows alphanumeric characters, dots, hyphens, percent signs, and plus or minus signs.
* - It requires an "@" symbol after the username.
* - It allows a domain consisting of alphanumeric characters, hyphens, and dots.
* - The domain must end with a dot followed by at least two alphabetic characters.
*/
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

if (!email.value) {
error.value = "L'e-mail est requis.";
} else if (!emailPattern.test(email.value)) {
error.value = "L'e-mail n'est pas valide.";
} else {
error.value = "";
return true;
}
};

/**
* Validates a phone number to ensure it is not empty and follows a valid phone number format.
*
* @returns {boolean} True if the phone number is valid, false otherwise.
*/
const validatePhone = () => {
/**
* Regular expression to validate a phone number:
* - It can optionally start with a plus sign (+).
* - It can then contain one or more digits (0-9), commas, periods, or whitespace.
* - The string must end after the allowed characters.
*/
const phonePattern = /^\+?[\d,. ]+$/;
if (!phone.value) {
error.value = "";
return true;
} else if (!phonePattern.test(phone.value)) {
error.value =
"Le téléphone doit contenir uniquement des chiffres, +, ,, . ou un espace.";
return false;
}
};

/**
* Validates whether a CAPTCHA field is empty.
*
* @returns {boolean} True if the CAPTCHA field is not empty, false otherwise.
*/
const validateCaptcha = () => {
if (!captcha.value) {
error.value = "Le captcha est requis.";
} else {
error.value = "";
return true;
}
};

/**
* Validates a complete form by executing a set of validation functions.
*
* @returns {boolean} True if all fields are valid, false otherwise.
*/
const validateForm = () => {
const validationFunctions = [
validateEmail, // Function to validate email
validatePhone, // Function to validate phone number
validateCaptcha, // Function to validate CAPTCHA
];

// Return true if all form fields are valid, otherwise return false.
return validationFunctions.every((validationFunction) =>
validationFunction(),
);
};
const error = ref("");
const success = ref("");

const submitForm = async () => {
if (validateForm()) {
const formData = {
firstname: firstname.value,
lastname: lastname.value,
company: company.value,
role: role.value,
phone: phone.value,
email: email.value,
message: message.value,
captcha: captcha.value,
};
const submitForm = async (event: Event) => {
const form = event.target as HTMLFormElement;
const formData = extractFormData(form);

if (validatePhone(formData.phone as string, error)) {
try {
await post("client_case", formData);
success.value = "Votre demande a bien été enregistrée";
form.reset();
} catch {
error.value = "Erreur d'envoi, veuillez réessayer plus tard.";
}
}
};

function getCaptcha(response: any) {
captcha.value = response;
}

let captcha = ref("");
const error = ref("");
const firstname = ref("");
const lastname = ref("");
const company = ref("");
const role = ref("");
const phone = ref("");
const email = ref("");
const message = ref("");
const success = ref("");
</script>

<style scoped lang="scss">
Expand Down
Loading
Loading