Form.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <template>
  2. <div>
  3. <v-card v-if="!jobApplicationSent">
  4. <v-card-title class="text-center">
  5. Formulaire de Candidature
  6. </v-card-title>
  7. <v-card-text>
  8. <v-form ref="form" validate-on="submit lazy" @submit.prevent="submit">
  9. <v-text-field
  10. id="jobApplicationName"
  11. v-model="jobApplication.name"
  12. :rules="[validateName]"
  13. label="Nom*"
  14. required
  15. />
  16. <v-text-field
  17. id="jobApplicationSurname"
  18. v-model="jobApplication.surname"
  19. :rules="[validateSurname]"
  20. label="Prénom*"
  21. required
  22. />
  23. <v-text-field
  24. id="jobApplicationPhone"
  25. v-model="jobApplication.phone"
  26. :rules="[validatePhone]"
  27. label="Téléphone*"
  28. required
  29. />
  30. <v-text-field
  31. id="jobApplicationEmail"
  32. v-model="jobApplication.email"
  33. :rules="[validateEmail]"
  34. label="Email*"
  35. required
  36. />
  37. <v-file-input
  38. id="jobApplicationResume"
  39. v-model="resumeUpload"
  40. :rules="[validateResume, validateFileSize]"
  41. label="Dépôt de CV*"
  42. accept=".pdf, .jpeg, .png"
  43. show-size
  44. required
  45. />
  46. <v-file-input
  47. id="jobApplicationMotivationLetter"
  48. v-model="motivationLetterUpload"
  49. :rules="[validateFileSize]"
  50. label="Dépôt de lettre de motivation"
  51. accept=".pdf, .jpeg, .png"
  52. show-size
  53. />
  54. <v-textarea
  55. id="jobApplicationMessage"
  56. v-model="jobApplication.message"
  57. :rules="[validateNonEmptyMessage, validateMessageLength]"
  58. label="Message*"
  59. required
  60. />
  61. <span class="remaining-cars-notice"
  62. >{{ leftCars }} caractères restants</span
  63. >
  64. <div class="d-flex flex-column align-center mt-4">
  65. <!-- @see https://github.com/hCaptcha/vue-hcaptcha -->
  66. <LayoutCaptcha />
  67. </div>
  68. </v-form>
  69. </v-card-text>
  70. <p class="text-right mr-6">* Champs obligatoires</p>
  71. <v-card-actions class="justify-center">
  72. <v-btn class="btn-more mb-4 submit" @click="submit"> Envoyer </v-btn>
  73. </v-card-actions>
  74. </v-card>
  75. </div>
  76. </template>
  77. <script setup lang="ts">
  78. import type { ComputedRef, Ref } from 'vue'
  79. import { reactive } from 'vue'
  80. import ContactRequest from '~/models/Maestro/ContactRequest'
  81. import { useEntityManager } from '~/composables/data/useEntityManager'
  82. import JobApplication from '~/models/Maestro/JobApplication'
  83. import FileUtils from '~/services/utils/FileUtils'
  84. const { em } = useEntityManager()
  85. const form: Ref<HTMLElement | null> = ref(null)
  86. const jobApplicationSent: Ref<boolean> = ref(false)
  87. const emit = defineEmits(['submit'])
  88. // @ts-ignore
  89. const jobApplication: ContactRequest = reactive(em.newInstance(JobApplication))
  90. const resumeUpload = ref(null)
  91. const motivationLetterUpload = ref(null)
  92. // --- Validation ---
  93. const maxMessageLength = 2000
  94. const leftCars: ComputedRef<number> = computed(
  95. () =>
  96. maxMessageLength -
  97. (jobApplication.message ? jobApplication.message.length : 0)
  98. )
  99. // Taille maximum en Mo
  100. const maxFileSize = 5
  101. const validateName = (name: string | null) => !!name || 'Le nom est obligatoire'
  102. const validateSurname = (surname: string | null) =>
  103. !!surname || 'Le prénom est obligatoire'
  104. const validateEmail = (email: string | null) =>
  105. (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide"
  106. const validatePhone = (email: string | null) =>
  107. (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) ||
  108. 'Le numéro de téléphone doit être valide'
  109. const validateResume = () =>
  110. (resumeUpload.value !== null && resumeUpload.value[0] !== null) ||
  111. "Vous devez joindre un CV à l'un des formats indiqués"
  112. const validateFileSize = () =>
  113. (resumeUpload.value !== null &&
  114. resumeUpload.value[0] !== null &&
  115. // @ts-ignore
  116. resumeUpload.value[0].size < maxFileSize * 1024 * 1024) ||
  117. 'La taille du fichier ne doit pas dépasser ' + maxFileSize + ' Mo'
  118. const validateNonEmptyMessage = (message: string | null) =>
  119. (!!message && message.length > 0) || 'Le message ne peut pas être vide'
  120. const validateMessageLength = (message: string | null) =>
  121. (!!message && message.length <= maxMessageLength) ||
  122. 'Le message ne doit pas dépasser ' + maxMessageLength + ' caractères'
  123. /**
  124. * Soumet le formulaire de candidature (boite de dialogue)
  125. */
  126. const submit = async () => {
  127. const { valid } = await form.value.validate()
  128. if (!valid) {
  129. jobApplicationSent.value = false
  130. return
  131. }
  132. jobApplication.resume =
  133. resumeUpload.value !== null && resumeUpload.value[0] !== null
  134. ? {
  135. // @ts-ignore
  136. name: resumeUpload.value[0].name,
  137. content: await FileUtils.blobToBase64(resumeUpload.value[0]),
  138. }
  139. : null
  140. jobApplication.motivationLetter =
  141. motivationLetterUpload.value !== null &&
  142. motivationLetterUpload.value[0] !== null
  143. ? {
  144. // @ts-ignore
  145. name: motivationLetterUpload.value[0].name,
  146. content: await FileUtils.blobToBase64(
  147. motivationLetterUpload.value[0]
  148. ),
  149. }
  150. : null
  151. await em.persist(JobApplication, jobApplication)
  152. jobApplicationSent.value = true
  153. emit('submit')
  154. }
  155. </script>
  156. <style scoped lang="scss">
  157. .submit {
  158. width: 100%;
  159. margin-bottom: 0 !important;
  160. height: 55px;
  161. background: var(--secondary-color);
  162. }
  163. .submit:hover {
  164. background-color: var(--on-neutral-color-extra-light);
  165. }
  166. </style>