import { Meta, Source } from '@storybook/addon-docs'
import '../../styles/shared.css';

<Meta title="Guide du dev/Classes utilitaires/Règles de validation" />


<div className="header">
  <h1>Règles de validation</h1>
  <p>Le Design System fournit un ensemble complet de règles de validation prêtes à l'emploi pour les formulaires Vuetify. Ces règles facilitent la validation des champs de formulaire tout en garantissant une expérience utilisateur cohérente. </p>
</div>

## Importation

<Source dark code={`import {
  doMatchPattern,
  isDateValid,
  isExactLength,
  isHolidayDay,
  isMaxLength,
  isMinLength,
  isNotAfterDate,
  isNotAfterToday,
  isNotBeforeDate,
  isNotBeforeToday,
  isRequired,
  isValidEmail
} from '@cnamts/synapse'
`}/>

## Règles disponibles

### isRequired

Vérifie qu'un champ n'est pas vide.

<Source dark code={`// Utilisation simple
isRequired()

// Avec message personnalisé
isRequired('Ce champ est obligatoire')

// Avec nom de champ
isRequired('Ce champ est obligatoire', 'Email')
`}/>

### isValidEmail

Vérifie qu'un champ contient une adresse email valide.

<Source dark code={`// Utilisation simple
isValidEmail()

// Avec message personnalisé
isValidEmail('Format d\\'email invalide')

// Avec nom de champ
isValidEmail('Format d\\'email invalide', 'Email professionnel')
`}/>

### isMinLength

Vérifie qu'un champ contient au moins un nombre minimum de caractères.

<Source dark code={`// Minimum 8 caractères
isMinLength(8)

// Avec message personnalisé
isMinLength(8, 'Doit contenir au moins {min} caractères')

// Avec nom de champ
isMinLength(8, 'Doit contenir au moins {min} caractères', 'Mot de passe')
`}/>

### isMaxLength

Vérifie qu'un champ ne dépasse pas un nombre maximum de caractères.

<Source dark code={`// Maximum 100 caractères
isMaxLength(100)

// Avec message personnalisé
isMaxLength(100, 'Ne doit pas dépasser {max} caractères')

// Avec nom de champ
isMaxLength(100, 'Ne doit pas dépasser {max} caractères', 'Description')
`}/>

### isExactLength

Vérifie qu'un champ contient exactement un nombre spécifique de caractères.

<Source dark code={`// Exactement 10 caractères
isExactLength(10)

// Avec message personnalisé
isExactLength(10, 'Doit contenir exactement {length} caractères')

// Avec nom de champ
isExactLength(10, 'Doit contenir exactement {length} caractères', 'Code')
`}/>

### doMatchPattern

Vérifie qu'un champ correspond à un motif d'expression régulière.

<Source dark code={`// Motif simple (lettres uniquement)
doMatchPattern(/^[a-zA-Z]+$/)

// Avec message personnalisé
doMatchPattern(/^[a-zA-Z]+$/, 'Doit contenir uniquement des lettres')

// Avec nom de champ
doMatchPattern(/^[a-zA-Z]+$/, 'Doit contenir uniquement des lettres', 'Nom')

// Exemple pour un mot de passe fort
doMatchPattern(
  // Regex pour mot de passe fort (commenté pour éviter les problèmes de parsing)
  // Doit contenir au moins une majuscule, une minuscule, un chiffre et un caractère spécial
  'REGEX_MOT_DE_PASSE_FORT',
  'Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule, un chiffre et un caractère spécial'
)
`}/>

### isDateValid

Vérifie qu'un champ contient une date valide.

<Source dark code={`// Utilisation simple
isDateValid()

// Avec message personnalisé
isDateValid('Date invalide')

// Avec nom de champ
isDateValid('Date invalide', 'Date de naissance')
`}/>

### isNotBeforeDate

Vérifie qu'une date n'est pas antérieure à une date spécifiée.

<Source dark code={`// Date de référence
isNotBeforeDate('01/01/2023')

// Avec message personnalisé
isNotBeforeDate('01/01/2023', 'La date doit être postérieure ou égale au {date}')

// Avec nom de champ
isNotBeforeDate('01/01/2023', 'La date doit être postérieure ou égale au {date}', 'Date de début')
`}/>

### isNotAfterDate

Vérifie qu'une date n'est pas postérieure à une date spécifiée.

<Source dark code={`// Date de référence
isNotAfterDate('31/12/2023')

// Avec message personnalisé
isNotAfterDate('31/12/2023', 'La date doit être antérieure ou égale au {date}')

// Avec nom de champ
isNotAfterDate('31/12/2023', 'La date doit être antérieure ou égale au {date}', 'Date de fin')
`}/>

### isNotBeforeToday

Vérifie qu'une date n'est pas antérieure à aujourd'hui.

<Source dark code={`// Utilisation simple
isNotBeforeToday()

// Avec message personnalisé
isNotBeforeToday('La date ne peut pas être dans le passé')

// Avec nom de champ
isNotBeforeToday('La date ne peut pas être dans le passé', 'Date de rendez-vous')
`}/>

### isNotAfterToday

Vérifie qu'une date n'est pas postérieure à aujourd'hui.

<Source dark code={`// Utilisation simple
isNotAfterToday()

// Avec message personnalisé
isNotAfterToday('La date ne peut pas être dans le futur')

// Avec nom de champ
isNotAfterToday('La date ne peut pas être dans le futur', 'Date de naissance')
`}/>

### isHolidayDay

Vérifie si une date correspond à un jour férié en France.

<Source dark code={`// Utilisation comme fonction de vérification
const isHoliday = isHolidayDay('25/12/2023')
console.log(isHoliday) // true (Noël)

// Utilisation comme règle de validation (avec négation)
v => !isHolidayDay(v) || 'La date ne peut pas être un jour férié'
`}/>

## Exemples d'utilisation

### Formulaire d'inscription simple

<Source dark code={`<template>
  <v-form ref="form" v-model="isFormValid">
    <v-text-field
      v-model="formData.email"
      label="Email"
      :rules="rules.email"
    />
    
    <v-text-field
      v-model="formData.password"
      label="Mot de passe"
      type="password"
      :rules="rules.password"
    />
    
    <v-text-field
      v-model="formData.confirmPassword"
      label="Confirmer le mot de passe"
      type="password"
      :rules="rules.confirmPassword"
    />
    
    <v-btn
      color="primary"
      :disabled="!isFormValid"
      @click="submitForm"
    >
      S'inscrire
    </v-btn>
  </v-form>
</template>

<script>
import { ref, reactive, computed } from 'vue'
import {
  isRequired,
  isValidEmail,
  isMinLength,
  doMatchPattern
} from '@cnamts/synapse'

export default {
  setup() {
    const form = ref(null)
    const isFormValid = ref(false)
    
    const formData = reactive({
      email: '',
      password: '',
      confirmPassword: ''
    })
    
    const rules = {
      email: [
        isRequired('Ce champ est requis', 'Email'),
        isValidEmail('Format d\\'email invalide', 'Email')
      ],
      password: [
        isRequired('Ce champ est requis', 'Mot de passe'),
        isMinLength(8, 'Doit contenir au moins {min} caractères', 'Mot de passe'),
        // Règle de validation pour mot de passe fort (simplifiée)
        v => v && v.match(/[A-Z]/) && v.match(/[a-z]/) && v.match(/[0-9]/) && v.match(/[^A-Za-z0-9]/) || 
            'Doit contenir au moins une majuscule, une minuscule, un chiffre et un caractère spécial'
      ],
      confirmPassword: [
        isRequired('Ce champ est requis', 'Confirmation du mot de passe'),
        v => v === formData.password || 'Les mots de passe ne correspondent pas'
      ]
    }
    
    const submitForm = () => {
      if (form.value.validate()) {
        // Traitement du formulaire
        console.log('Formulaire valide', formData)
      }
    }
    
    return {
      form,
      isFormValid,
      formData,
      rules,
      submitForm
    }
  }
}
</script>
`}/>

### Formulaire de réservation avec validation de dates

<Source dark code={`<template>
  <v-form ref="form" v-model="isFormValid">
    <v-text-field
      v-model="formData.name"
      label="Nom complet"
      :rules="rules.name"
    />
    
    <v-text-field
      v-model="formData.startDate"
      label="Date de début"
      placeholder="JJ/MM/AAAA"
      :rules="rules.startDate"
    />
    
    <v-text-field
      v-model="formData.endDate"
      label="Date de fin"
      placeholder="JJ/MM/AAAA"
      :rules="rules.endDate"
    />
    
    <v-btn
      color="primary"
      :disabled="!isFormValid"
      @click="submitForm"
    >
      Réserver
    </v-btn>
  </v-form>
</template>

<script>
import { ref, reactive, computed } from '
import '../../styles/shared.css';vue'
import {
  isRequired,
  isDateValid,
  isNotBeforeToday,
  isNotAfterDate,
  isHolidayDay
} from '@cnamts/synapse'

export default {
  setup() {
    const form = ref(null)
    const isFormValid = ref(false)
    
    const formData = reactive({
      name: '',
      startDate: '',
      endDate: ''
    })
    
    // Date limite (6 mois à partir d'aujourd'hui)
    const maxDate = new Date()
    maxDate.setMonth(maxDate.getMonth() + 6)
    const maxDateFormatted = maxDate.getDate().toString().padStart(2, '0') + '/' + 
                            (maxDate.getMonth() + 1).toString().padStart(2, '0') + '/' + 
                            maxDate.getFullYear()
    
    // Fonction utilitaire pour vérifier si une date est après une autre
    const isDateAfter = (date1, date2) => {
      // Implémentation simplifiée
      return true || 'La date de fin doit être après la date de début'
    }
    
    const rules = {
      name: [
        isRequired('Ce champ est requis', 'Nom')
      ],
      startDate: [
        isRequired('Ce champ est requis', 'Date de début'),
        isDateValid('Format de date invalide (JJ/MM/AAAA)', 'Date de début'),
        isNotBeforeToday('La date ne peut pas être dans le passé', 'Date de début'),
        isNotAfterDate(maxDateFormatted, 'La date doit être avant le {date}', 'Date de début'),
        v => !isHolidayDay(v) || 'La date ne peut pas être un jour férié'
      ],
      endDate: computed(() => [
        isRequired('Ce champ est requis', 'Date de fin'),
        isDateValid('Format de date invalide (JJ/MM/AAAA)', 'Date de fin'),
        v => !formData.startDate || !isDateValid()(formData.startDate) === true || 
             !isDateValid()(v) === true || 
             isDateAfter(v, formData.startDate),
        isNotAfterDate(maxDateFormatted, 'La date doit être avant le {date}', 'Date de fin'),
        v => !isHolidayDay(v) || 'La date ne peut pas être un jour férié'
      ])
    }
    
    const submitForm = () => {
      if (form.value.validate()) {
        // Traitement du formulaire
        console.log('Formulaire valide', formData)
      }
    }
    
    return {
      form,
      isFormValid,
      formData,
      rules,
      submitForm
    }
  }
}
</script>
`}/>

## Combinaison de règles personnalisées et prédéfinies

Vous pouvez facilement combiner les règles prédéfinies avec vos propres règles personnalisées :

<Source dark code={`const rules = {
  username: [
    isRequired(),
    isMinLength(3),
    isMaxLength(20),
    // Règle personnalisée pour valider le format du nom d'utilisateur
    v => v && /^[a-z0-9_-]+$/.test(v) || 
        'Le nom d\\'utilisateur ne peut contenir que des lettres minuscules, chiffres, tirets et underscores'
  ],
  phoneNumber: [
    // Règle conditionnelle - validation uniquement si une valeur est fournie
    v => !v || /^(0|\\+33)[1-9](\\d{2}){4}$/.test(v) || 
        'Format de numéro de téléphone invalide'
  ]
}
`}/>

## Bonnes pratiques

- Utilisez des noms de champs dans vos règles pour des messages d'erreur plus clairs
- Combinez plusieurs règles pour une validation complète
- Utilisez des règles calculées (computed) lorsque la validation dépend d'autres champs
- Personnalisez les messages d'erreur pour qu'ils soient compréhensibles par les utilisateurs
- Validez toujours les données côté serveur, même si vous avez une validation côté client
- Pour les formulaires complexes, envisagez d'utiliser une bibliothèque de validation comme VeeValidate en complément

## Référence complète

Pour plus de détails sur l'utilisation des règles, consultez la [documentation complète des règles de validation](?path=/docs/guide-du-dev-r%C3%A8gles-de-validation-les-r%C3%A8gles-de-validation--docs).
