@cnamts/synapse 0.0.14-alpha → 0.0.16-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CookiesSelection/CookiesSelection.d.ts +26 -26
- package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -2
- package/dist/components/Customs/SySelect/SySelect.d.ts +24 -12
- package/dist/components/Customs/SySelect/locales.d.ts +3 -0
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +1393 -3
- package/dist/components/DatePicker/DatePicker.d.ts +3532 -22
- package/dist/components/DatePicker/DateTextInput.d.ts +1408 -11
- package/dist/components/DialogBox/config.d.ts +1 -1
- package/dist/components/DownloadBtn/DownloadBtn.d.ts +2 -0
- package/dist/components/LangBtn/LangBtn.d.ts +467 -1
- package/dist/components/LangBtn/config.d.ts +1 -3
- package/dist/components/NirField/NirField.d.ts +2805 -15
- package/dist/components/PasswordField/PasswordField.d.ts +2 -2
- package/dist/components/PeriodField/PeriodField.d.ts +7345 -325
- package/dist/components/PhoneField/PhoneField.d.ts +3 -3
- package/dist/components/SelectBtnField/SelectBtnField.d.ts +1 -1
- package/dist/components/SkipLink/SkipLink.d.ts +3 -2
- package/dist/components/SyAlert/SyAlert.d.ts +72 -1
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +26 -26
- package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +2 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/composables/date/useDateFormat.d.ts +2 -2
- package/dist/composables/date/useDateFormatDayjs.d.ts +23 -0
- package/dist/composables/date/useDateInitializationDayjs.d.ts +18 -0
- package/dist/design-system-v3.js +4314 -3987
- package/dist/design-system-v3.umd.cjs +1 -1
- package/dist/style.css +1 -1
- package/dist/vuetifyConfig.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/BackBtn/Accessibilite.stories.ts +4 -0
- package/src/components/BackBtn/BackBtn.vue +2 -1
- package/src/components/BackToTopBtn/Accessibilite.stories.ts +4 -0
- package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +78 -21
- package/src/components/BackToTopBtn/BackToTopBtn.vue +15 -0
- package/src/components/BackToTopBtn/config.ts +2 -2
- package/src/components/BackToTopBtn/tests/__snapshots__/BackToTopBtn.spec.ts.snap +4 -4
- package/src/components/CopyBtn/Accessibilite.stories.ts +4 -0
- package/src/components/Customs/SyBtnSelect/SyBtnSelect.stories.ts +2 -2
- package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +0 -1
- package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +3 -3
- package/src/components/Customs/SyInputSelect/SyInputSelect.vue +4 -4
- package/src/components/Customs/SySelect/SySelect.stories.ts +4 -0
- package/src/components/Customs/SySelect/SySelect.vue +75 -10
- package/src/components/Customs/SySelect/locales.ts +3 -0
- package/src/components/Customs/SySelect/tests/SySelect.spec.ts +24 -2
- package/src/components/Customs/SyTextField/Accessibilite.stories.ts +7 -0
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +14 -1
- package/src/components/Customs/SyTextField/SyTextField.vue +85 -20
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +795 -0
- package/src/components/DatePicker/DatePicker.stories.ts +432 -1
- package/src/components/DatePicker/DatePicker.vue +143 -76
- package/src/components/DatePicker/DatePickerValidation.mdx +338 -0
- package/src/components/DatePicker/DatePickerValidation.stories.ts +30 -0
- package/src/components/DatePicker/DateTextInput.vue +87 -135
- package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +282 -0
- package/src/components/DatePicker/docExamples/DatePickerValidationExamples.vue +535 -0
- package/src/components/DatePicker/tests/DatePicker.spec.ts +33 -32
- package/src/components/DatePicker/tests/DateTextInput.spec.ts +83 -35
- package/src/components/DialogBox/DialogBox.stories.ts +5 -2
- package/src/components/DialogBox/DialogBox.vue +1 -1
- package/src/components/DialogBox/config.ts +1 -1
- package/src/components/DownloadBtn/Accessibilite.stories.ts +4 -0
- package/src/components/DownloadBtn/DownloadBtn.stories.ts +17 -8
- package/src/components/DownloadBtn/DownloadBtn.vue +13 -6
- package/src/components/DownloadBtn/tests/__snapshots__/DownloadBtn.spec.ts.snap +0 -2
- package/src/components/FranceConnectBtn/Accessibilite.stories.ts +4 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +3 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +3 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/menu.scss +19 -0
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +12 -2
- package/src/components/LangBtn/Accessibilite.stories.ts +4 -0
- package/src/components/LangBtn/LangBtn.stories.ts +1 -4
- package/src/components/LangBtn/LangBtn.vue +68 -9
- package/src/components/LangBtn/config.ts +0 -1
- package/src/components/LangBtn/tests/LangBtn.spec.ts +30 -2
- package/src/components/PageContainer/Accessibilite.stories.ts +36 -23
- package/src/components/PaginatedTable/PaginatedTable.stories.ts +144 -18
- package/src/components/PasswordField/PasswordField.stories.ts +6 -6
- package/src/components/PasswordField/PasswordField.vue +3 -3
- package/src/components/PeriodField/PeriodField.vue +4 -4
- package/src/components/PhoneField/PhoneField.stories.ts +216 -24
- package/src/components/PhoneField/PhoneField.vue +32 -2
- package/src/components/PhoneField/tests/PhoneField.spec.ts +161 -14
- package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +2 -1
- package/src/components/RatingPicker/RatingPicker.stories.ts +1 -1
- package/src/components/SkipLink/Accessibilite.stories.ts +8 -0
- package/src/components/SkipLink/SkipLink.vue +11 -9
- package/src/components/SkipLink/tests/__snapshots__/skipLink.spec.ts.snap +7 -4
- package/src/components/SkipLink/tests/skipLink.spec.ts +120 -6
- package/src/components/SyAlert/Accessibilite.stories.ts +4 -0
- package/src/components/SyAlert/SyAlert.mdx +3 -7
- package/src/components/SyAlert/SyAlert.stories.ts +19 -12
- package/src/components/SyAlert/SyAlert.vue +88 -51
- package/src/components/SyAlert/tests/SyAlert.spec.ts +20 -2
- package/src/components/SyAlert/tests/__snapshots__/SyAlert.spec.ts.snap +83 -75
- package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +56 -0
- package/src/components/UserMenuBtn/UserMenuBtn.vue +4 -2
- package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +41 -0
- package/src/components/index.ts +2 -0
- package/src/composables/date/useDateFormat.ts +17 -1
- package/src/composables/date/useDateFormatDayjs.ts +84 -0
- package/src/composables/date/useDateInitializationDayjs.ts +133 -0
- package/src/composables/rules/useFieldValidation.ts +26 -3
- package/src/stories/Accessibilite/Avancement/Avancement.mdx +12 -0
- package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +134 -0
- package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +1 -1
- package/src/stories/GuideDuDev/LesBreackingChanges.mdx +31 -2
- package/src/components/LangBtn/tests/Config.spec.ts +0 -24
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
2
|
import DatePicker from './DatePicker.vue'
|
|
3
|
-
import { ref } from 'vue'
|
|
3
|
+
import { ref, watch, computed } from 'vue'
|
|
4
|
+
import { useDateFormat } from '@/composables/date/useDateFormatDayjs'
|
|
4
5
|
|
|
5
6
|
const meta = {
|
|
6
7
|
title: 'Composants/Formulaires/DatePicker',
|
|
@@ -1199,6 +1200,436 @@ export const NoCalendarWithErrorDisabled: Story = {
|
|
|
1199
1200
|
},
|
|
1200
1201
|
}
|
|
1201
1202
|
|
|
1203
|
+
export const WithDayjsFormat: Story = {
|
|
1204
|
+
parameters: {
|
|
1205
|
+
sourceCode: [
|
|
1206
|
+
{
|
|
1207
|
+
name: 'Template',
|
|
1208
|
+
code: `
|
|
1209
|
+
<template>
|
|
1210
|
+
<div>
|
|
1211
|
+
<DatePicker
|
|
1212
|
+
v-model="date"
|
|
1213
|
+
placeholder="Sélectionner une date"
|
|
1214
|
+
format="DD/MM/YYYY"
|
|
1215
|
+
/>
|
|
1216
|
+
<p class="mt-4">Date formatée avec dayjs: {{ formattedDate }}</p>
|
|
1217
|
+
<p>Date parsée avec dayjs: {{ parsedDate ? parsedDate.toLocaleDateString() : 'Aucune date' }}</p>
|
|
1218
|
+
</div>
|
|
1219
|
+
</template>
|
|
1220
|
+
`,
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
name: 'Script',
|
|
1224
|
+
code: `
|
|
1225
|
+
<script setup lang="ts">
|
|
1226
|
+
import { ref, watch } from 'vue'
|
|
1227
|
+
import { DatePicker } from '@cnamts/synapse'
|
|
1228
|
+
import { useDateFormat } from '@cnamts/synapse'
|
|
1229
|
+
|
|
1230
|
+
const { parseDate, formatDate } = useDateFormat()
|
|
1231
|
+
|
|
1232
|
+
const date = ref('')
|
|
1233
|
+
const formattedDate = ref('')
|
|
1234
|
+
const parsedDate = ref<Date | null>(null)
|
|
1235
|
+
|
|
1236
|
+
watch(date, (newDate) => {
|
|
1237
|
+
if (newDate) {
|
|
1238
|
+
parsedDate.value = parseDate(newDate, 'DD/MM/YYYY')
|
|
1239
|
+
if (parsedDate.value) {
|
|
1240
|
+
formattedDate.value = formatDate(parsedDate.value, 'YYYY-MM-DD')
|
|
1241
|
+
}
|
|
1242
|
+
} else {
|
|
1243
|
+
formattedDate.value = ''
|
|
1244
|
+
parsedDate.value = null
|
|
1245
|
+
}
|
|
1246
|
+
})
|
|
1247
|
+
</script>
|
|
1248
|
+
`,
|
|
1249
|
+
},
|
|
1250
|
+
],
|
|
1251
|
+
},
|
|
1252
|
+
args: {
|
|
1253
|
+
placeholder: 'Sélectionner une date',
|
|
1254
|
+
format: 'DD/MM/YYYY',
|
|
1255
|
+
isBirthDate: false,
|
|
1256
|
+
showWeekNumber: false,
|
|
1257
|
+
required: false,
|
|
1258
|
+
displayRange: false,
|
|
1259
|
+
displayIcon: true,
|
|
1260
|
+
displayAppendIcon: false,
|
|
1261
|
+
disabled: false,
|
|
1262
|
+
noIcon: false,
|
|
1263
|
+
noCalendar: false,
|
|
1264
|
+
modelValue: '',
|
|
1265
|
+
},
|
|
1266
|
+
render: () => {
|
|
1267
|
+
return {
|
|
1268
|
+
components: { DatePicker },
|
|
1269
|
+
setup() {
|
|
1270
|
+
// Importer le composable useDateFormat depuis useDateFormatDayjs
|
|
1271
|
+
const { parseDate, formatDate } = useDateFormat()
|
|
1272
|
+
|
|
1273
|
+
const date = ref('')
|
|
1274
|
+
const formattedDate = ref('')
|
|
1275
|
+
const parsedDate = ref<Date | null>(null)
|
|
1276
|
+
|
|
1277
|
+
watch(date, (newDate) => {
|
|
1278
|
+
if (newDate) {
|
|
1279
|
+
parsedDate.value = parseDate(newDate, 'DD/MM/YYYY')
|
|
1280
|
+
if (parsedDate.value) {
|
|
1281
|
+
formattedDate.value = formatDate(parsedDate.value, 'YYYY-MM-DD')
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
formattedDate.value = ''
|
|
1286
|
+
parsedDate.value = null
|
|
1287
|
+
}
|
|
1288
|
+
})
|
|
1289
|
+
|
|
1290
|
+
return { date, formattedDate, parsedDate }
|
|
1291
|
+
},
|
|
1292
|
+
|
|
1293
|
+
template: `
|
|
1294
|
+
<div class="pa-4">
|
|
1295
|
+
<DatePicker
|
|
1296
|
+
v-model="date"
|
|
1297
|
+
placeholder="Sélectionner une date"
|
|
1298
|
+
format="DD/MM/YYYY"
|
|
1299
|
+
/>
|
|
1300
|
+
<p class="mt-4">Date formatée avec dayjs: {{ formattedDate }}</p>
|
|
1301
|
+
<p>Date parsée avec dayjs: {{ parsedDate ? parsedDate.toLocaleDateString() : 'Aucune date' }}</p>
|
|
1302
|
+
</div>
|
|
1303
|
+
`,
|
|
1304
|
+
}
|
|
1305
|
+
},
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
export const BidirectionalValidation: Story = {
|
|
1309
|
+
parameters: {
|
|
1310
|
+
sourceCode: [
|
|
1311
|
+
{
|
|
1312
|
+
name: 'Template',
|
|
1313
|
+
code: `
|
|
1314
|
+
<template>
|
|
1315
|
+
<div class="date-validation-playground">
|
|
1316
|
+
<h1>Validation bidirectionnelle des dates</h1>
|
|
1317
|
+
<p class="description">
|
|
1318
|
+
Démonstration de la validation bidirectionnelle entre les DatePickers.
|
|
1319
|
+
Les messages d'erreur apparaissent directement dans les composants.
|
|
1320
|
+
</p>
|
|
1321
|
+
<div class="date-range-container">
|
|
1322
|
+
<div class="date-picker-wrapper">
|
|
1323
|
+
<h3>Date de début</h3>
|
|
1324
|
+
<DatePicker
|
|
1325
|
+
ref="startDatePickerRef"
|
|
1326
|
+
v-model="startDate"
|
|
1327
|
+
placeholder="Date de début"
|
|
1328
|
+
:custom-rules="startDateRules"
|
|
1329
|
+
required
|
|
1330
|
+
@update:model-value="validateEndDate"
|
|
1331
|
+
/>
|
|
1332
|
+
</div>
|
|
1333
|
+
<div class="date-picker-wrapper">
|
|
1334
|
+
<h3>Date de fin</h3>
|
|
1335
|
+
<DatePicker
|
|
1336
|
+
ref="endDatePickerRef"
|
|
1337
|
+
v-model="endDate"
|
|
1338
|
+
placeholder="Date de fin"
|
|
1339
|
+
:custom-rules="endDateRules"
|
|
1340
|
+
required
|
|
1341
|
+
@update:model-value="validateStartDate"
|
|
1342
|
+
/>
|
|
1343
|
+
</div>
|
|
1344
|
+
</div>
|
|
1345
|
+
<div class="current-values">
|
|
1346
|
+
<p><strong>Date de début:</strong> {{ startDate || 'Non sélectionnée' }}</p>
|
|
1347
|
+
<p><strong>Date de fin:</strong> {{ endDate || 'Non sélectionnée' }}</p>
|
|
1348
|
+
</div>
|
|
1349
|
+
</div>
|
|
1350
|
+
</template>
|
|
1351
|
+
`,
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
name: 'Script',
|
|
1355
|
+
code: `
|
|
1356
|
+
<script lang="ts" setup>
|
|
1357
|
+
import { ref, watch, computed } from 'vue'
|
|
1358
|
+
import DatePicker from '@cnamts/synapse'
|
|
1359
|
+
import { useDateFormat } from '@cnamts/synapse'
|
|
1360
|
+
|
|
1361
|
+
const { parseDate } = useDateFormat()
|
|
1362
|
+
|
|
1363
|
+
// État des dates
|
|
1364
|
+
const startDate = ref<string | null>(null)
|
|
1365
|
+
const endDate = ref<string | null>(null)
|
|
1366
|
+
|
|
1367
|
+
// Références aux composants DatePicker pour accéder à leurs méthodes
|
|
1368
|
+
const startDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1369
|
+
const endDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1370
|
+
|
|
1371
|
+
// Règle de validation pour vérifier que la date de fin n'est pas avant la date de début
|
|
1372
|
+
const createEndDateValidationRule = () => ({
|
|
1373
|
+
type: 'custom',
|
|
1374
|
+
options: {
|
|
1375
|
+
validate: (value: string) => {
|
|
1376
|
+
// Si pas de valeur pour la date de fin, pas besoin de validation
|
|
1377
|
+
if (!value) return true
|
|
1378
|
+
|
|
1379
|
+
// Si pas de date de début mais une date de fin, afficher l'erreur
|
|
1380
|
+
if (!startDate.value) return 'Veuillez d'abord sélectionner une date de début'
|
|
1381
|
+
|
|
1382
|
+
const start = parseDate(startDate.value, 'DD/MM/YYYY')
|
|
1383
|
+
const end = parseDate(value, 'DD/MM/YYYY')
|
|
1384
|
+
|
|
1385
|
+
if (!start || !end) return true
|
|
1386
|
+
|
|
1387
|
+
return end >= start || 'La date de fin ne peut pas être antérieure à la date de début'
|
|
1388
|
+
},
|
|
1389
|
+
message: 'La date de fin ne peut pas être antérieure à la date de début',
|
|
1390
|
+
},
|
|
1391
|
+
})
|
|
1392
|
+
|
|
1393
|
+
// Règle de validation pour vérifier que la date de début n'est pas après la date de fin
|
|
1394
|
+
const createStartDateValidationRule = () => ({
|
|
1395
|
+
type: 'custom',
|
|
1396
|
+
options: {
|
|
1397
|
+
validate: (value: string) => {
|
|
1398
|
+
// Si pas de valeur pour la date de début ou pas de date de fin, pas besoin de validation
|
|
1399
|
+
if (!value || !endDate.value) return true
|
|
1400
|
+
|
|
1401
|
+
const start = parseDate(value, 'DD/MM/YYYY')
|
|
1402
|
+
const end = parseDate(endDate.value, 'DD/MM/YYYY')
|
|
1403
|
+
|
|
1404
|
+
if (!start || !end) return true
|
|
1405
|
+
|
|
1406
|
+
return start <= end || 'La date de début ne peut pas être postérieure à la date de fin'
|
|
1407
|
+
},
|
|
1408
|
+
message: 'La date de début ne peut pas être postérieure à la date de fin',
|
|
1409
|
+
},
|
|
1410
|
+
})
|
|
1411
|
+
|
|
1412
|
+
// Règles de validation pour la date de début
|
|
1413
|
+
const startDateRules = computed(() => [
|
|
1414
|
+
{
|
|
1415
|
+
type: 'required',
|
|
1416
|
+
options: {
|
|
1417
|
+
message: 'La date de début est requise.',
|
|
1418
|
+
},
|
|
1419
|
+
},
|
|
1420
|
+
createStartDateValidationRule(),
|
|
1421
|
+
])
|
|
1422
|
+
|
|
1423
|
+
// Règles de validation pour la date de fin
|
|
1424
|
+
const endDateRules = computed(() => [
|
|
1425
|
+
{
|
|
1426
|
+
type: 'required',
|
|
1427
|
+
options: {
|
|
1428
|
+
message: 'La date de fin est requise.',
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
createEndDateValidationRule(),
|
|
1432
|
+
])
|
|
1433
|
+
|
|
1434
|
+
// Fonction pour forcer la validation de la date de fin quand la date de début change
|
|
1435
|
+
const validateEndDate = () => {
|
|
1436
|
+
if (endDatePickerRef.value && endDate.value) {
|
|
1437
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1438
|
+
endDatePickerRef.value.validateOnSubmit()
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// Fonction pour forcer la validation de la date de début quand la date de fin change
|
|
1443
|
+
const validateStartDate = () => {
|
|
1444
|
+
if (startDatePickerRef.value && startDate.value) {
|
|
1445
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1446
|
+
startDatePickerRef.value.validateOnSubmit()
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// Watcher pour la date de début qui force la revalidation de la date de fin
|
|
1451
|
+
watch(startDate, () => {
|
|
1452
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1453
|
+
setTimeout(() => {
|
|
1454
|
+
validateEndDate()
|
|
1455
|
+
}, 0)
|
|
1456
|
+
})
|
|
1457
|
+
|
|
1458
|
+
// Watcher pour la date de fin qui force la revalidation de la date de début
|
|
1459
|
+
watch(endDate, () => {
|
|
1460
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1461
|
+
setTimeout(() => {
|
|
1462
|
+
validateStartDate()
|
|
1463
|
+
}, 0)
|
|
1464
|
+
})
|
|
1465
|
+
</script>
|
|
1466
|
+
`,
|
|
1467
|
+
},
|
|
1468
|
+
],
|
|
1469
|
+
},
|
|
1470
|
+
render: () => {
|
|
1471
|
+
return {
|
|
1472
|
+
components: { DatePicker },
|
|
1473
|
+
setup() {
|
|
1474
|
+
// Importer le composable useDateFormat depuis useDateFormatDayjs
|
|
1475
|
+
const { parseDate } = useDateFormat()
|
|
1476
|
+
|
|
1477
|
+
// État des dates
|
|
1478
|
+
const startDate = ref<string | null>(null)
|
|
1479
|
+
const endDate = ref<string | null>(null)
|
|
1480
|
+
|
|
1481
|
+
// Références aux composants DatePicker pour accéder à leurs méthodes
|
|
1482
|
+
const startDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1483
|
+
const endDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1484
|
+
|
|
1485
|
+
// Règle de validation pour vérifier que la date de fin n'est pas avant la date de début
|
|
1486
|
+
const createEndDateValidationRule = () => ({
|
|
1487
|
+
type: 'custom',
|
|
1488
|
+
options: {
|
|
1489
|
+
validate: (value: string) => {
|
|
1490
|
+
// Si pas de valeur pour la date de fin, pas besoin de validation
|
|
1491
|
+
if (!value) return true
|
|
1492
|
+
|
|
1493
|
+
// Si pas de date de début mais une date de fin, afficher l'erreur
|
|
1494
|
+
if (!startDate.value) return 'Veuillez d\'abord sélectionner une date de début'
|
|
1495
|
+
|
|
1496
|
+
const start = parseDate(startDate.value, 'DD/MM/YYYY')
|
|
1497
|
+
const end = parseDate(value, 'DD/MM/YYYY')
|
|
1498
|
+
|
|
1499
|
+
if (!start || !end) return true
|
|
1500
|
+
|
|
1501
|
+
return end >= start || 'La date de fin ne peut pas être antérieure à la date de début'
|
|
1502
|
+
},
|
|
1503
|
+
message: 'La date de fin ne peut pas être antérieure à la date de début',
|
|
1504
|
+
},
|
|
1505
|
+
})
|
|
1506
|
+
|
|
1507
|
+
// Règle de validation pour vérifier que la date de début n'est pas après la date de fin
|
|
1508
|
+
const createStartDateValidationRule = () => ({
|
|
1509
|
+
type: 'custom',
|
|
1510
|
+
options: {
|
|
1511
|
+
validate: (value: string) => {
|
|
1512
|
+
// Si pas de valeur pour la date de début ou pas de date de fin, pas besoin de validation
|
|
1513
|
+
if (!value || !endDate.value) return true
|
|
1514
|
+
|
|
1515
|
+
const start = parseDate(value, 'DD/MM/YYYY')
|
|
1516
|
+
const end = parseDate(endDate.value, 'DD/MM/YYYY')
|
|
1517
|
+
|
|
1518
|
+
if (!start || !end) return true
|
|
1519
|
+
|
|
1520
|
+
return start <= end || 'La date de début ne peut pas être postérieure à la date de fin'
|
|
1521
|
+
},
|
|
1522
|
+
message: 'La date de début ne peut pas être postérieure à la date de fin',
|
|
1523
|
+
},
|
|
1524
|
+
})
|
|
1525
|
+
|
|
1526
|
+
// Règles de validation pour la date de début
|
|
1527
|
+
const startDateRules = computed(() => [
|
|
1528
|
+
{
|
|
1529
|
+
type: 'required',
|
|
1530
|
+
options: {
|
|
1531
|
+
message: 'La date de début est requise.',
|
|
1532
|
+
},
|
|
1533
|
+
},
|
|
1534
|
+
createStartDateValidationRule(),
|
|
1535
|
+
])
|
|
1536
|
+
|
|
1537
|
+
// Règles de validation pour la date de fin
|
|
1538
|
+
const endDateRules = computed(() => [
|
|
1539
|
+
{
|
|
1540
|
+
type: 'required',
|
|
1541
|
+
options: {
|
|
1542
|
+
message: 'La date de fin est requise.',
|
|
1543
|
+
},
|
|
1544
|
+
},
|
|
1545
|
+
createEndDateValidationRule(),
|
|
1546
|
+
])
|
|
1547
|
+
|
|
1548
|
+
// Fonction pour forcer la validation de la date de fin quand la date de début change
|
|
1549
|
+
const validateEndDate = () => {
|
|
1550
|
+
if (endDatePickerRef.value && endDate.value) {
|
|
1551
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1552
|
+
endDatePickerRef.value.validateOnSubmit()
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Fonction pour forcer la validation de la date de début quand la date de fin change
|
|
1557
|
+
const validateStartDate = () => {
|
|
1558
|
+
if (startDatePickerRef.value && startDate.value) {
|
|
1559
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1560
|
+
startDatePickerRef.value.validateOnSubmit()
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
// Watcher pour la date de début qui force la revalidation de la date de fin
|
|
1565
|
+
watch(startDate, () => {
|
|
1566
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1567
|
+
setTimeout(() => {
|
|
1568
|
+
validateEndDate()
|
|
1569
|
+
}, 0)
|
|
1570
|
+
})
|
|
1571
|
+
|
|
1572
|
+
// Watcher pour la date de fin qui force la revalidation de la date de début
|
|
1573
|
+
watch(endDate, () => {
|
|
1574
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1575
|
+
setTimeout(() => {
|
|
1576
|
+
validateStartDate()
|
|
1577
|
+
}, 0)
|
|
1578
|
+
})
|
|
1579
|
+
|
|
1580
|
+
return {
|
|
1581
|
+
startDate,
|
|
1582
|
+
endDate,
|
|
1583
|
+
startDatePickerRef,
|
|
1584
|
+
endDatePickerRef,
|
|
1585
|
+
startDateRules,
|
|
1586
|
+
endDateRules,
|
|
1587
|
+
validateEndDate,
|
|
1588
|
+
validateStartDate,
|
|
1589
|
+
}
|
|
1590
|
+
},
|
|
1591
|
+
|
|
1592
|
+
template: `
|
|
1593
|
+
<div class="date-validation-playground">
|
|
1594
|
+
<h1>Validation bidirectionnelle des dates</h1>
|
|
1595
|
+
<p class="description">
|
|
1596
|
+
Démonstration de la validation bidirectionnelle entre les DatePickers.
|
|
1597
|
+
Les messages d'erreur apparaissent directement dans les composants.
|
|
1598
|
+
</p>
|
|
1599
|
+
<div class="date-range-container">
|
|
1600
|
+
<div class="date-picker-wrapper">
|
|
1601
|
+
<h3>Date de début</h3>
|
|
1602
|
+
<DatePicker
|
|
1603
|
+
ref="startDatePickerRef"
|
|
1604
|
+
v-model="startDate"
|
|
1605
|
+
placeholder="Date de début"
|
|
1606
|
+
:custom-rules="startDateRules"
|
|
1607
|
+
required
|
|
1608
|
+
@update:model-value="validateEndDate"
|
|
1609
|
+
/>
|
|
1610
|
+
</div>
|
|
1611
|
+
<div class="date-picker-wrapper">
|
|
1612
|
+
<h3>Date de fin</h3>
|
|
1613
|
+
<DatePicker
|
|
1614
|
+
ref="endDatePickerRef"
|
|
1615
|
+
v-model="endDate"
|
|
1616
|
+
placeholder="Date de fin"
|
|
1617
|
+
:custom-rules="endDateRules"
|
|
1618
|
+
required
|
|
1619
|
+
@update:model-value="validateStartDate"
|
|
1620
|
+
/>
|
|
1621
|
+
</div>
|
|
1622
|
+
</div>
|
|
1623
|
+
<div class="current-values">
|
|
1624
|
+
<p><strong>Date de début:</strong> {{ startDate || 'Non sélectionnée' }}</p>
|
|
1625
|
+
<p><strong>Date de fin:</strong> {{ endDate || 'Non sélectionnée' }}</p>
|
|
1626
|
+
</div>
|
|
1627
|
+
</div>
|
|
1628
|
+
`,
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1202
1633
|
export const WithFormSubmission: Story = {
|
|
1203
1634
|
parameters: {
|
|
1204
1635
|
sourceCode: [
|