Création du composant MovieCommentForm, début de mise en place de la lofgique, a…
…vec rules de validation.
Showing
4 changed files
with
166 additions
and
3 deletions
components/form/MovieCommentForm.vue
0 → 100644
| 1 | +<script lang="ts" setup> | ||
| 2 | +import { useVuelidate } from "@vuelidate/core"; | ||
| 3 | +import { helpers, maxLength, minLength, required, minValue, maxValue } from "@vuelidate/validators"; | ||
| 4 | + | ||
| 5 | +// type FormData = { | ||
| 6 | +// username: string | ||
| 7 | +// message: string | ||
| 8 | +// rating: number | ||
| 9 | +// }; | ||
| 10 | + | ||
| 11 | +type FormData = { [key: string]: string|number }; | ||
| 12 | + | ||
| 13 | +//#region --Data/ref--. | ||
| 14 | +const initialState = { | ||
| 15 | + username: "", | ||
| 16 | + message: "", | ||
| 17 | + rating: 5, | ||
| 18 | +}; | ||
| 19 | + | ||
| 20 | +// Validation rules | ||
| 21 | +const rules = { | ||
| 22 | + username: { | ||
| 23 | + required: helpers.withMessage("Le nom d'utilisateur est requis", required), | ||
| 24 | + minLength: helpers.withMessage("Le nom d'utilisateur doit contenir au moins 3 caractères", minLength(3)), | ||
| 25 | + maxLength: helpers.withMessage("Le nom d'utilisateur ne peut pas dépasser 50 caractères", maxLength(50)), | ||
| 26 | + alpha: helpers.withMessage( | ||
| 27 | + "Le nom d'utilisateur ne peut contenir que des lettres", | ||
| 28 | + helpers.regex(/^[a-zA-ZÀ-ÿ\s]+$/), | ||
| 29 | + ), | ||
| 30 | + }, | ||
| 31 | + message: { | ||
| 32 | + required: helpers.withMessage("Le message est requis", required), | ||
| 33 | + minLength: helpers.withMessage("Le message doit contenir au moins 3 caractères", minLength(3)), | ||
| 34 | + maxLength: helpers.withMessage("Le message ne peut pas dépasser 500 caractères", maxLength(500)), | ||
| 35 | + }, | ||
| 36 | + rating:{ | ||
| 37 | + required: helpers.withMessage("La notation est requise", required), | ||
| 38 | + minValue: helpers.withMessage("Le message ne être inférieure à 0", minValue(0)), | ||
| 39 | + maxValue: helpers.withMessage("Le message ne être suppérieur à 10", maxValue(10)), | ||
| 40 | + } | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +const formData = reactive({ | ||
| 44 | + ...initialState, | ||
| 45 | +}); | ||
| 46 | +const v$ = useVuelidate(rules, formData); | ||
| 47 | +//#endregion | ||
| 48 | + | ||
| 49 | +function submitComment() { | ||
| 50 | + console.log("Submit !") | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +function clear () { | ||
| 54 | + v$.value.$reset(); | ||
| 55 | + formData.username = initialState.username; | ||
| 56 | + formData.message = initialState.message; | ||
| 57 | + formData.rating = initialState.rating; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// :error-messages="getErrors('username', $v.username)" :counter="10" label="username" | ||
| 61 | +// :error-messages="getErrors('message', $v.message)" | ||
| 62 | +</script> | ||
| 63 | + | ||
| 64 | +<template> | ||
| 65 | + <section> | ||
| 66 | + movie comment form | ||
| 67 | + <VForm @submit.prevent="submitComment"> | ||
| 68 | + <v-text-field | ||
| 69 | + v-model="formData.username" | ||
| 70 | + :error-messages="v$.username.$errors.map(e => e.$message)" | ||
| 71 | + label="nom d'utilisateur" | ||
| 72 | + placeholder="nom d'utilisateur" | ||
| 73 | + required | ||
| 74 | + @blur="v$.username.$touch()" | ||
| 75 | + @input="v$.username.$touch()" | ||
| 76 | + /> | ||
| 77 | + <v-textarea | ||
| 78 | + v-model="formData.message" | ||
| 79 | + :error-messages="v$.message.$errors.map(e => e.$message)" | ||
| 80 | + label="message" | ||
| 81 | + placeholder="Saisissez votre commentaire" | ||
| 82 | + required | ||
| 83 | + @blur="v$.message.$touch" | ||
| 84 | + @input="v$.message.$touch" | ||
| 85 | + /> | ||
| 86 | + <v-text-field | ||
| 87 | + v-model="formData.rating" | ||
| 88 | + :error-messages="v$.rating.$errors.map(e => e.$message)" | ||
| 89 | + label="Note (1-10)" | ||
| 90 | + placeholder="" | ||
| 91 | + required | ||
| 92 | + type="number" | ||
| 93 | + @blur="v$.rating.$touch" | ||
| 94 | + @input="v$.rating.$touch" | ||
| 95 | + /> | ||
| 96 | + <v-btn class="mr-4">submit</v-btn> | ||
| 97 | + </VForm> | ||
| 98 | + </section> | ||
| 99 | +</template> | ||
| 100 | + | ||
| 101 | +<style scoped></style> |
| @@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
| 17 | "@nuxt/ui": "^2.22.0", | 17 | "@nuxt/ui": "^2.22.0", |
| 18 | "@pinia-orm/nuxt": "^1.10.2", | 18 | "@pinia-orm/nuxt": "^1.10.2", |
| 19 | "@pinia/nuxt": "^0.9.0", | 19 | "@pinia/nuxt": "^0.9.0", |
| 20 | + "@types/vuelidate": "^0.7.22", | ||
| 20 | "@unhead/vue": "^2.0.8", | 21 | "@unhead/vue": "^2.0.8", |
| 21 | "@vuelidate/core": "^2.0.3", | 22 | "@vuelidate/core": "^2.0.3", |
| 22 | "@vuelidate/validators": "^2.0.4", | 23 | "@vuelidate/validators": "^2.0.4", |
| @@ -4636,6 +4637,64 @@ | @@ -4636,6 +4637,64 @@ | ||
| 4636 | "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", | 4637 | "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", |
| 4637 | "license": "MIT" | 4638 | "license": "MIT" |
| 4638 | }, | 4639 | }, |
| 4640 | + "node_modules/@types/vuelidate": { | ||
| 4641 | + "version": "0.7.22", | ||
| 4642 | + "resolved": "https://registry.npmjs.org/@types/vuelidate/-/vuelidate-0.7.22.tgz", | ||
| 4643 | + "integrity": "sha512-bD3pP9FgL3pxMVQ9NJ3d8BbV8Ij6xsrDKdCO4l1Wq/AksXxRRmQ9lmYjRJwn/hLMcgWO/k0QdULfZWpRz13adw==", | ||
| 4644 | + "license": "MIT", | ||
| 4645 | + "dependencies": { | ||
| 4646 | + "vue": "^2.7.15" | ||
| 4647 | + } | ||
| 4648 | + }, | ||
| 4649 | + "node_modules/@types/vuelidate/node_modules/@vue/compiler-sfc": { | ||
| 4650 | + "version": "2.7.16", | ||
| 4651 | + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz", | ||
| 4652 | + "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==", | ||
| 4653 | + "dependencies": { | ||
| 4654 | + "@babel/parser": "^7.23.5", | ||
| 4655 | + "postcss": "^8.4.14", | ||
| 4656 | + "source-map": "^0.6.1" | ||
| 4657 | + }, | ||
| 4658 | + "optionalDependencies": { | ||
| 4659 | + "prettier": "^1.18.2 || ^2.0.0" | ||
| 4660 | + } | ||
| 4661 | + }, | ||
| 4662 | + "node_modules/@types/vuelidate/node_modules/prettier": { | ||
| 4663 | + "version": "2.8.8", | ||
| 4664 | + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", | ||
| 4665 | + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", | ||
| 4666 | + "license": "MIT", | ||
| 4667 | + "optional": true, | ||
| 4668 | + "bin": { | ||
| 4669 | + "prettier": "bin-prettier.js" | ||
| 4670 | + }, | ||
| 4671 | + "engines": { | ||
| 4672 | + "node": ">=10.13.0" | ||
| 4673 | + }, | ||
| 4674 | + "funding": { | ||
| 4675 | + "url": "https://github.com/prettier/prettier?sponsor=1" | ||
| 4676 | + } | ||
| 4677 | + }, | ||
| 4678 | + "node_modules/@types/vuelidate/node_modules/source-map": { | ||
| 4679 | + "version": "0.6.1", | ||
| 4680 | + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", | ||
| 4681 | + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", | ||
| 4682 | + "license": "BSD-3-Clause", | ||
| 4683 | + "engines": { | ||
| 4684 | + "node": ">=0.10.0" | ||
| 4685 | + } | ||
| 4686 | + }, | ||
| 4687 | + "node_modules/@types/vuelidate/node_modules/vue": { | ||
| 4688 | + "version": "2.7.16", | ||
| 4689 | + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", | ||
| 4690 | + "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==", | ||
| 4691 | + "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.", | ||
| 4692 | + "license": "MIT", | ||
| 4693 | + "dependencies": { | ||
| 4694 | + "@vue/compiler-sfc": "2.7.16", | ||
| 4695 | + "csstype": "^3.1.0" | ||
| 4696 | + } | ||
| 4697 | + }, | ||
| 4639 | "node_modules/@types/web-bluetooth": { | 4698 | "node_modules/@types/web-bluetooth": { |
| 4640 | "version": "0.0.21", | 4699 | "version": "0.0.21", |
| 4641 | "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", | 4700 | "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", |
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | "@nuxt/ui": "^2.22.0", | 23 | "@nuxt/ui": "^2.22.0", |
| 24 | "@pinia-orm/nuxt": "^1.10.2", | 24 | "@pinia-orm/nuxt": "^1.10.2", |
| 25 | "@pinia/nuxt": "^0.9.0", | 25 | "@pinia/nuxt": "^0.9.0", |
| 26 | + "@types/vuelidate": "^0.7.22", | ||
| 26 | "@unhead/vue": "^2.0.8", | 27 | "@unhead/vue": "^2.0.8", |
| 27 | "@vuelidate/core": "^2.0.3", | 28 | "@vuelidate/core": "^2.0.3", |
| 28 | "@vuelidate/validators": "^2.0.4", | 29 | "@vuelidate/validators": "^2.0.4", |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | //#region --import--. | 2 | //#region --import--. |
| 3 | -import { ArrowLeftIcon, FilmIcon } from "lucide-vue-next"; | 3 | +import { ArrowLeftIcon } from "lucide-vue-next"; |
| 4 | import { useTMDB } from "~/composables/tMDB"; | 4 | import { useTMDB } from "~/composables/tMDB"; |
| 5 | import { computed, onMounted, ref } from "vue"; | 5 | import { computed, onMounted, ref } from "vue"; |
| 6 | import { Movie } from "~/models/movie"; | 6 | import { Movie } from "~/models/movie"; |
| @@ -125,7 +125,7 @@ onMounted(() => { | @@ -125,7 +125,7 @@ onMounted(() => { | ||
| 125 | <!-- Contenu du film --> | 125 | <!-- Contenu du film --> |
| 126 | <div v-else-if="movie" class="relative"> | 126 | <div v-else-if="movie" class="relative"> |
| 127 | <!-- Backdrop image --> | 127 | <!-- Backdrop image --> |
| 128 | - <ui-components-backdrop-image v-if="movie.backdrop_path" :src="movie.poster_path" :title="movie.title" /> | 128 | + <ui-components-backdrop-image v-if="movie.backdrop_path" :src="movie.backdrop_path" :title="movie.title" /> |
| 129 | 129 | ||
| 130 | <!-- Contenu principal --> | 130 | <!-- Contenu principal --> |
| 131 | <div class="container mx-auto px-4 py-8 relative z-10 pt-20"> | 131 | <div class="container mx-auto px-4 py-8 relative z-10 pt-20"> |
| @@ -170,12 +170,14 @@ onMounted(() => { | @@ -170,12 +170,14 @@ onMounted(() => { | ||
| 170 | <span class="font-semibold">Têtes d'affiche:</span> | 170 | <span class="font-semibold">Têtes d'affiche:</span> |
| 171 | {{ | 171 | {{ |
| 172 | movie.credit.cast | 172 | movie.credit.cast |
| 173 | - .slice(0, 5) | 173 | + .slice(0, 10) |
| 174 | .map((person) => person.name) | 174 | .map((person) => person.name) |
| 175 | .join(", ") | 175 | .join(", ") |
| 176 | }} | 176 | }} |
| 177 | </div> | 177 | </div> |
| 178 | </div> | 178 | </div> |
| 179 | + <!-- Comments form. --> | ||
| 180 | + <form-movie-comment-form /> | ||
| 179 | </section> | 181 | </section> |
| 180 | </div> | 182 | </div> |
| 181 | </div> | 183 | </div> |
-
Please register or login to post a comment