import type { Meta, StoryObj } from '@storybook/vue3-vite' import PeriodField from './PeriodField.vue' import { ref } from 'vue' // Type pour les méthodes exposées par PeriodField type ValidationMessage = { type: string, message: string }[] interface PeriodFieldExpose { validateOnSubmit: () => boolean errors: Record successes: Record warnings: Record isValid: boolean } const meta: Meta = { title: 'Composants/Formulaires/PeriodField', component: PeriodField, decorators: [ () => ({ template: '
', }), ], parameters: { layout: 'fullscreen', controls: { exclude: ['modelValue'] }, }, argTypes: { locales: { description: 'Surcharge des chaînes affichées à l\'utilisateur (messages de validation des dates de début et de fin). Les valeurs par défaut sont définies dans le fichier `locales.ts` du composant. La prop accepte un objet partiel : seules les clés renseignées surchargent les valeurs par défaut, le reste est conservé.', control: 'object', table: { type: { summary: 'object', detail: `{ fromAfterTo: string, fromValid: string, fromRequired: string, fromFilled: string, toBeforeFrom: string, toValid: string, toRequired: string, toFilled: string, }` }, category: 'props', }, }, modelValue: { control: 'text', description: 'Valeur du champ', table: { type: { summary: 'object', }, }, }, placeholderFrom: { control: 'text', description: 'Placeholder pour la date de début', }, placeholderTo: { control: 'text', description: 'Placeholder pour la date de fin', }, format: { control: 'select', options: ['DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY-MM-DD'], description: 'Format d\'affichage de la date', }, dateFormatReturn: { control: 'select', options: ['', 'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY-MM-DD'], description: 'Format de la date pour la valeur de retour', }, isOutlined: { control: 'boolean', description: 'Affiche le champ en contour', }, required: { control: 'boolean', description: 'Champ obligatoire', }, displayIcon: { control: 'boolean', description: 'Affiche l\'icône calendrier', }, displayAppendIcon: { control: 'boolean', description: 'Icône à la fin du champ', }, disabled: { control: 'boolean', description: 'Désactive le champ', }, noIcon: { control: 'boolean', description: 'Masque toutes les icônes', }, noCalendar: { control: 'boolean', description: 'Désactive le calendrier', }, customRules: { control: 'object', description: 'Règles de validation', }, customWarningRules: { control: 'object', description: 'Règles d\'avertissement', }, disableErrorHandling: { control: 'boolean', description: 'Désactive la gestion des erreurs', }, showSuccessMessages: { control: 'boolean', description: 'Affiche les messages de succès', }, errors: { description: 'Tableaux réactif contenant tous les messages d\'erreur. Combine les erreurs injectées via errorMessages et celles générées par la validation. Les doublons sont supprimés et le tableau est limité selon maxErrors. Accessible via template ref du composant.', table: { type: { summary: `{ fromDate: Readonly>, toDate: Readonly> }` }, category: 'expose', }, }, warnings: { description: 'Tableaux réactif contenant tous les messages d\'avertissement. Combine les avertissements injectés via warningMessages et ceux générés par customWarningRules. Les doublons sont supprimés et le tableau est limité selon maxErrors. Accessible via template ref du composant.', table: { type: { summary: `{ fromDate: Readonly>, toDate: Readonly> }` }, category: 'expose', }, }, successes: { description: 'Tableaux réactif contenant tous les messages de succès. Combine les succès injectés via successMessages et ceux générés par customSuccessRules. Les doublons sont supprimés et le tableau est limité selon maxErrors. Accessible via template ref du composant.', table: { type: { summary: `{ fromDate: Readonly>, toDate: Readonly> }` }, category: 'expose', }, }, isValid: { description: 'Vrai si le champ est valide.', table: { type: { summary: 'boolean' }, category: 'expose', }, }, validateOnSubmit: { description: 'Fonction qui permet de déclencher la validation du champ.', table: { type: { summary: '() => promise' }, category: 'expose', }, }, clearValidation: { description: 'Fonction qui permet de réinitialiser la validation du champ.', table: { type: { summary: '() => void' }, category: 'expose', }, }, }, } as Meta export default meta type Story = StoryObj export const Default: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: false, displayIcon: true, displayAppendIcon: false, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const CustomPlaceholders: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début de la période', placeholderTo: 'Fin de la période', format: 'DD/MM/YYYY', dateFormatReturn: '', required: false, displayIcon: true, displayAppendIcon: false, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const Disabled: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: false, displayIcon: true, displayAppendIcon: false, disabled: true, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `
`, }), } export const Required: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: true, displayIcon: true, displayAppendIcon: false, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const AppendIcon: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', required: true, displayIcon: true, displayAppendIcon: true, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const WithoutIcon: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: true, displayIcon: false, displayAppendIcon: true, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: null, to: null }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const WithError: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: true, displayIcon: false, displayAppendIcon: true, disabled: false, noIcon: false, modelValue: { from: '01/01/2100', to: '05/01/2100' }, customRules: [ { type: 'notAfterToday', options: { message: 'La date ne peut pas être après aujourd\'hui' } }, ], }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: '01/01/2100', to: '05/01/2100' }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const WithWarning: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: true, displayIcon: false, displayAppendIcon: true, disabled: false, noIcon: false, modelValue: { from: '20/12/2023', to: '21/12/2023' }, customWarningRules: [ { type: 'notBeforeDate', options: { warningMessage: 'Attention : les dates sont antérieures au 02/01/2031', date: '02/01/2031', isWarning: true, }, }, ], }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: '20/12/2023', to: '21/12/2023' }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const WithSuccess: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', displayIcon: false, displayAppendIcon: true, disabled: false, noIcon: false, showSuccessMessages: true, modelValue: { from: '22/01/2024', to: '23/01/2024' }, customRules: [ { type: 'notWeekend', options: { message: 'La date ne peut pas être un weekend', successMessage: 'La date n\'est pas un week-end', }, }, ], }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value = ref({ from: '22/01/2024', to: '23/01/2024' }) return { args, value } }, template: `

Période sélectionnée : {{ value }}

`, }), } export const DifferentFormats: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: false, displayIcon: true, displayAppendIcon: false, disabled: false, noIcon: false, modelValue: { from: '12/10/2023', to: '15/10/2023' }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value1 = ref({ from: '12/10/2023', to: '15/10/2023' }) const value2 = ref({ from: '10/12/2023', to: '10/15/2023' }) const value3 = ref({ from: '2023-10-12', to: '2023-10-15' }) const value4 = ref({ from: '12-10-23', to: '15-10-23' }) const value5 = ref({ from: '12.10.2023', to: '15.10.2023' }) return { args, value1, value2, value3, value4, value5 } }, template: `
`, }), } export const WithDateFormatReturn: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { placeholderFrom: 'Début', placeholderTo: 'Fin', format: 'DD/MM/YYYY', dateFormatReturn: '', required: false, displayIcon: true, displayAppendIcon: false, disabled: false, noIcon: false, modelValue: { from: null, to: null }, }, render: args => ({ components: { PeriodField: PeriodField }, setup() { const value1 = ref({ from: '12/10/2023', to: '15/10/2023' }) const value2 = ref({ from: '12/10/2023', to: '15/10/2023' }) const value3 = ref({ from: '12/10/2023', to: '15/10/2023' }) const valueReturn1 = ref({ from: '12/10/2023', to: '15/10/2023' }) const valueReturn2 = ref({ from: '10/12/2023', to: '10/15/2023' }) const valueReturn3 = ref({ from: '2023/12/10', to: '2023/15/10' }) return { args, value1, value2, value3, valueReturn1, valueReturn2, valueReturn3 } }, template: `
Période de retour : {{ valueReturn1 }}

Période de retour : {{ valueReturn2 }}

Période de retour : {{ valueReturn3 }}

`, }), } export const ValidationBehaviors: Story = { parameters: { sourceCode: [ { code: ` `, }, ], }, render: args => ({ components: { PeriodField }, setup() { const periodDefault = ref({ from: null, to: null }) const periodNoErrors = ref({ from: null, to: null }) const periodNoSuccess = ref({ from: null, to: null }) const periodNoValidation = ref({ from: null, to: null }) return { args, periodDefault, periodNoErrors, periodNoSuccess, periodNoValidation, } }, template: `

Par défaut (avec validation)

Validation désactivée (disableErrorHandling=true)

Messages de succès désactivés (showSuccessMessages=false)

Validation et messages de succès désactivés

`, }), } export const FormValidation: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, render: () => ({ components: { PeriodField }, setup() { // Référence au formulaire const formRef = ref(null) const periodFieldRef = ref(null) const isSubmitting = ref(false) const isFormSubmitted = ref(false) const formData = ref(null) const formStatus = ref('') // Données du formulaire const form = ref({ period: { from: null, to: null }, }) // Règles de validation pour le champ période const periodRules = [ { type: 'notAfterToday', options: { message: 'La date ne peut pas être après aujourdhui' } }, ] // Soumission du formulaire const submitForm = async (): Promise => { if (periodFieldRef.value) { const isValid = await periodFieldRef.value.validateOnSubmit() if (isValid) { formStatus.value = 'Formulaire soumis avec succès !' isFormSubmitted.value = true formData.value = JSON.stringify(form.value) } else { formStatus.value = 'Erreur de validation, veuillez corriger les champs' } } } return { formRef, periodFieldRef, isSubmitting, isFormSubmitted, formData, form, periodRules, formStatus, submitForm, } }, template: `

Formulaire avec validation

Valider
{{ formStatus }}
{{ formData }}
`, }), }