Kaynağa Gözat

add cursus and contact sections

olinox14 1 yıl önce
ebeveyn
işleme
6fd53b2417
6 değiştirilmiş dosya ile 220 ekleme ve 3 silme
  1. BIN
      .yarn/install-state.gz
  2. 124 0
      components/Contact.vue
  3. 44 0
      components/Cursus.vue
  4. 21 1
      lang/en.json
  5. 21 1
      lang/fr.json
  6. 10 1
      pages/index.vue

BIN
.yarn/install-state.gz


+ 124 - 0
components/Contact.vue

@@ -0,0 +1,124 @@
+<template>
+  <div>
+    <div id="anchor" />
+
+    <v-form
+      v-if="!contactRequestSent"
+      ref="form"
+      validate-on="submit lazy"
+      @submit.prevent="submit"
+    >
+      <v-container>
+        <v-row>
+          <v-col cols="12" md="6">
+            <v-text-field
+              v-model="email"
+              :rules="[validateEmail]"
+              :label="$t('contact_email')"
+              required
+              type="email"
+            />
+          </v-col>
+
+          <v-col cols="12" md="6">
+            <v-text-field
+              v-model="name"
+              :label="$t('contact_name')"
+              required
+            />
+          </v-col>
+        </v-row>
+
+        <v-row>
+          <v-col cols="12">
+            <v-textarea
+              v-model="message"
+              :rules="[validateNonEmptyMessage]"
+              :label="$t('contact_message')"
+              required
+              maxlength="400"
+            />
+          </v-col>
+        </v-row>
+
+        <!-- Submit Button -->
+        <div class="d-flex flex-row justify-center">
+          <v-btn
+            type="submit"
+            variant="outlined"
+            :height="54"
+            :width="180"
+            class="submit-btn"
+          >
+            {{ $t('contact_submit') }}
+          </v-btn>
+        </div>
+
+        <div v-if="errorMsg" class="error">
+          {{ errorMsg }}
+        </div>
+      </v-container>
+    </v-form>
+
+    <div v-else class="confirmation-message d-flex flex-row justify-center">
+      <v-card>
+        <v-icon icon="fas fa-check mr-1" />
+        {{ $t('contact_confirmation') }}
+      </v-card>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import type { Ref } from '@vue/reactivity'
+
+const router = useRouter()
+
+const form: Ref<HTMLElement | null> = ref(null)
+
+const contactRequestSent: Ref<boolean> = ref(false)
+
+const errorMsg: Ref<string | null> = ref(null)
+
+const email: Ref<string | null> = ref(null)
+const name: Ref<string | null> = ref(null)
+const message: Ref<string | null> = ref(null)
+
+const validateEmail = (email: string | null) =>
+  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide"
+
+const validateNonEmptyMessage = (message: string | null) =>
+  (!!message && message.length > 0) || 'Le message ne peut pas être vide'
+
+
+/**
+ * Submits the contact form.
+ *
+ * This function validates the form and sets the value of a variable to indicate whether the form submission was successful.
+ *
+ * @function
+ *
+ * @returns {void}
+ */
+const submit = async (): Promise<void> => {
+  const { valid } = await form.value!.validate()
+
+  if (!valid) {
+    contactRequestSent.value = false
+    return
+  }
+
+  // TODO: send email
+
+  contactRequestSent.value = true
+  errorMsg.value = null
+
+  // Défile vers le début de page pour afficher le message de confirmation
+  setTimeout(() => router.push({ path: '', hash: '#anchor' }), 30)
+}
+
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 44 - 0
components/Cursus.vue

@@ -0,0 +1,44 @@
+<template>
+  <v-table>
+    <tbody>
+    <tr
+      v-for="item in items"
+      :key="item.label"
+    >
+      <td>{{ item.year }}</td>
+      <td>{{ item.label }}</td>
+    </tr>
+    </tbody>
+  </v-table>
+</template>
+
+<script setup lang="ts">
+  import type { Ref } from '@vue/reactivity'
+
+  const i18n = useI18n()
+
+  const items: Ref<Array<{ label: string, year: string }>> = ref([
+    { year: '2007-2008', label: i18n.t('cursus_prepa') },
+    { year: '2008-2011', label: i18n.t('cursus_engees') },
+    { year: '2010', label: i18n.t('cursus_bafia') },
+    { year: '2011', label: i18n.t('cursus_imfs') },
+    { year: '2012', label: i18n.t('cursus_public_exam') },
+    { year: '2011-2016', label: i18n.t('cursus_sag_67') },
+    { year: '2013', label: i18n.t('cursus_management') },
+    { year: '2014', label: i18n.t('cursus_reporting') },
+    { year: '2016-2018', label: i18n.t('cursus_dsi_67') },
+    { year: '2016', label: i18n.t('cursus_dotnet') },
+    { year: '2016', label: i18n.t('cursus_scrum') },
+    { year: '2018-2019', label: i18n.t('cursus_mn') },
+    { year: '2020-2024', label: i18n.t('cursus_2ios') },
+  ])
+
+
+</script>
+
+<style scoped lang="scss">
+  .v-table {
+    max-width: 720px;
+    margin: 12px auto;
+  }
+</style>

+ 21 - 1
lang/en.json

@@ -11,5 +11,25 @@
   "Find me on Stackoverflow": "Find me on Stackoverflow",
   "Find me on LinkedIn": "Find me on LinkedIn",
   "Find me on Codingame": "Find me on Codingame",
-  "Competences": "Competences"
+  "Competences": "Competences",
+  "Cursus": "Cursus",
+  "Contact": "Contact",
+  "cursus_prepa": "Preparatory class (Physics-Chemistry)",
+  "cursus_engees": "National School of Water and Environmental Engineering of Strasbourg (ENGEES)",
+  "cursus_bafia": "Mission to implement a waste management plan, with IRCOD Alsace (NGO), in Bafia (Cameroon)",
+  "cursus_imfs": "Validation of a thesis on the modeling of the behavior of micropollutants in artificial wetlands, at the University of Strasbourg (Institute of fluid mechanics)",
+  "cursus_public_exam": "Admission competition in the Public Service",
+  "cursus_sag_67": "Project Manager Information Systems Applied to the Environment, at the Bas-Rhin Departmental Council (67)",
+  "cursus_management": "Training: Management",
+  "cursus_reporting": "Training: Communication and Reporting",
+  "cursus_dsi_67": "Project Manager Development SI, at the Bas-Rhin Departmental Council (67)",
+  "cursus_dotnet": "Training: .Net MVC",
+  "cursus_scrum": "Training: Scrum",
+  "cursus_mn": "Project Manager Development SI, at Digital Manche (50)",
+  "cursus_2ios": "Developer at 2iOpenService (74)",
+  "contact_email": "Your email address",
+  "contact_name": "Name or organization (optional)",
+  "contact_message": "Message",
+  "contact_submit": "Send",
+  "contact_confirmation": "Your message has been sent, I will get back to you as soon as possible"
 }

+ 21 - 1
lang/fr.json

@@ -11,5 +11,25 @@
   "Find me on Stackoverflow": "Retrouvez moi sur Stackoverflow",
   "Find me on LinkedIn": "Retrouvez moi sur LinkedIn",
   "Find me on Codingame": "Retrouvez moi sur Codingame",
-  "Competences": "Competences"
+  "Competences": "Competences",
+  "Cursus": "Cursus",
+  "Contact": "Contact",
+  "cursus_prepa": "Classe préparatoire (Physique-Chimie)",
+  "cursus_engees": "Ecole Nationale du Génie de l’Eau et de l’Environnement de Strasbourg (ENGEES)",
+  "cursus_bafia": "Mission de mise en place d’un plan de gestion des déchets, avec l’IRCOD Alsace (ONG), à Bafia (Cameroun)",
+  "cursus_imfs": "Validation d’une thèse sur la modélisation du comportement des micropolluants en zone humides artificielles, à l’Université de Strasbourg (Institut de mécanique des fluides)",
+  "cursus_public_exam": "Concours d’admission dans la fonction publique",
+  "cursus_sag_67": "Chef de projet Systèmes d’informations appliqués à l’Environnement, au Conseil Départemental du Bas-Rhin (67)",
+  "cursus_management": "Formation: Management",
+  "cursus_reporting": "Formation: Communication et Reporting",
+  "cursus_dsi_67": "Chef de projet Développement SI, au Conseil Départemental du Bas-Rhin (67)",
+  "cursus_dotnet": "Formation: .Net MVC",
+  "cursus_scrum": "Formation: Scrum",
+  "cursus_mn": "Chef de projet Développement SI, à Manche Numérique (50)",
+  "cursus_2ios": "Développeur à 2iOpenService (74)",
+  "contact_email": "Votre adresse e-mail",
+  "contact_name": "Nom ou structure (facultatif)",
+  "contact_message": "Message",
+  "contact_submit": "Envoyer",
+  "contact_confirmation": "Votre message a bien été envoyé, je reviendrais vers vous dès que possible"
 }

+ 10 - 1
pages/index.vue

@@ -155,10 +155,15 @@
   <div class="cursus">
     <h3>{{ $t("Cursus") }}</h3>
 
+    <Cursus />
+  </div>
 
+  <div class="cursus">
+    <h3>{{ $t("Contact") }}</h3>
 
-
+    <Contact />
   </div>
+
 </template>
 
 <script setup lang="ts">
@@ -220,6 +225,10 @@ const XP_YEARS = CURRENT_YEAR - START_YEAR
   }
 }
 
+h3 {
+  margin: 12px 0 24px 0;
+}
+
 .badges {
   .v-col {
     display: flex;