@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.
Files changed (108) hide show
  1. package/dist/components/CookiesSelection/CookiesSelection.d.ts +26 -26
  2. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -2
  3. package/dist/components/Customs/SySelect/SySelect.d.ts +24 -12
  4. package/dist/components/Customs/SySelect/locales.d.ts +3 -0
  5. package/dist/components/Customs/SyTextField/SyTextField.d.ts +1393 -3
  6. package/dist/components/DatePicker/DatePicker.d.ts +3532 -22
  7. package/dist/components/DatePicker/DateTextInput.d.ts +1408 -11
  8. package/dist/components/DialogBox/config.d.ts +1 -1
  9. package/dist/components/DownloadBtn/DownloadBtn.d.ts +2 -0
  10. package/dist/components/LangBtn/LangBtn.d.ts +467 -1
  11. package/dist/components/LangBtn/config.d.ts +1 -3
  12. package/dist/components/NirField/NirField.d.ts +2805 -15
  13. package/dist/components/PasswordField/PasswordField.d.ts +2 -2
  14. package/dist/components/PeriodField/PeriodField.d.ts +7345 -325
  15. package/dist/components/PhoneField/PhoneField.d.ts +3 -3
  16. package/dist/components/SelectBtnField/SelectBtnField.d.ts +1 -1
  17. package/dist/components/SkipLink/SkipLink.d.ts +3 -2
  18. package/dist/components/SyAlert/SyAlert.d.ts +72 -1
  19. package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +26 -26
  20. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +2 -0
  21. package/dist/components/index.d.ts +2 -0
  22. package/dist/composables/date/useDateFormat.d.ts +2 -2
  23. package/dist/composables/date/useDateFormatDayjs.d.ts +23 -0
  24. package/dist/composables/date/useDateInitializationDayjs.d.ts +18 -0
  25. package/dist/design-system-v3.js +4314 -3987
  26. package/dist/design-system-v3.umd.cjs +1 -1
  27. package/dist/style.css +1 -1
  28. package/dist/vuetifyConfig.d.ts +1 -0
  29. package/package.json +1 -1
  30. package/src/components/BackBtn/Accessibilite.stories.ts +4 -0
  31. package/src/components/BackBtn/BackBtn.vue +2 -1
  32. package/src/components/BackToTopBtn/Accessibilite.stories.ts +4 -0
  33. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +78 -21
  34. package/src/components/BackToTopBtn/BackToTopBtn.vue +15 -0
  35. package/src/components/BackToTopBtn/config.ts +2 -2
  36. package/src/components/BackToTopBtn/tests/__snapshots__/BackToTopBtn.spec.ts.snap +4 -4
  37. package/src/components/CopyBtn/Accessibilite.stories.ts +4 -0
  38. package/src/components/Customs/SyBtnSelect/SyBtnSelect.stories.ts +2 -2
  39. package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +0 -1
  40. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +3 -3
  41. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +4 -4
  42. package/src/components/Customs/SySelect/SySelect.stories.ts +4 -0
  43. package/src/components/Customs/SySelect/SySelect.vue +75 -10
  44. package/src/components/Customs/SySelect/locales.ts +3 -0
  45. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +24 -2
  46. package/src/components/Customs/SyTextField/Accessibilite.stories.ts +7 -0
  47. package/src/components/Customs/SyTextField/SyTextField.stories.ts +14 -1
  48. package/src/components/Customs/SyTextField/SyTextField.vue +85 -20
  49. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +795 -0
  50. package/src/components/DatePicker/DatePicker.stories.ts +432 -1
  51. package/src/components/DatePicker/DatePicker.vue +143 -76
  52. package/src/components/DatePicker/DatePickerValidation.mdx +338 -0
  53. package/src/components/DatePicker/DatePickerValidation.stories.ts +30 -0
  54. package/src/components/DatePicker/DateTextInput.vue +87 -135
  55. package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +282 -0
  56. package/src/components/DatePicker/docExamples/DatePickerValidationExamples.vue +535 -0
  57. package/src/components/DatePicker/tests/DatePicker.spec.ts +33 -32
  58. package/src/components/DatePicker/tests/DateTextInput.spec.ts +83 -35
  59. package/src/components/DialogBox/DialogBox.stories.ts +5 -2
  60. package/src/components/DialogBox/DialogBox.vue +1 -1
  61. package/src/components/DialogBox/config.ts +1 -1
  62. package/src/components/DownloadBtn/Accessibilite.stories.ts +4 -0
  63. package/src/components/DownloadBtn/DownloadBtn.stories.ts +17 -8
  64. package/src/components/DownloadBtn/DownloadBtn.vue +13 -6
  65. package/src/components/DownloadBtn/tests/__snapshots__/DownloadBtn.spec.ts.snap +0 -2
  66. package/src/components/FranceConnectBtn/Accessibilite.stories.ts +4 -0
  67. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +3 -0
  68. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +3 -0
  69. package/src/components/HeaderBar/HeaderBurgerMenu/menu.scss +19 -0
  70. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +12 -2
  71. package/src/components/LangBtn/Accessibilite.stories.ts +4 -0
  72. package/src/components/LangBtn/LangBtn.stories.ts +1 -4
  73. package/src/components/LangBtn/LangBtn.vue +68 -9
  74. package/src/components/LangBtn/config.ts +0 -1
  75. package/src/components/LangBtn/tests/LangBtn.spec.ts +30 -2
  76. package/src/components/PageContainer/Accessibilite.stories.ts +36 -23
  77. package/src/components/PaginatedTable/PaginatedTable.stories.ts +144 -18
  78. package/src/components/PasswordField/PasswordField.stories.ts +6 -6
  79. package/src/components/PasswordField/PasswordField.vue +3 -3
  80. package/src/components/PeriodField/PeriodField.vue +4 -4
  81. package/src/components/PhoneField/PhoneField.stories.ts +216 -24
  82. package/src/components/PhoneField/PhoneField.vue +32 -2
  83. package/src/components/PhoneField/tests/PhoneField.spec.ts +161 -14
  84. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +2 -1
  85. package/src/components/RatingPicker/RatingPicker.stories.ts +1 -1
  86. package/src/components/SkipLink/Accessibilite.stories.ts +8 -0
  87. package/src/components/SkipLink/SkipLink.vue +11 -9
  88. package/src/components/SkipLink/tests/__snapshots__/skipLink.spec.ts.snap +7 -4
  89. package/src/components/SkipLink/tests/skipLink.spec.ts +120 -6
  90. package/src/components/SyAlert/Accessibilite.stories.ts +4 -0
  91. package/src/components/SyAlert/SyAlert.mdx +3 -7
  92. package/src/components/SyAlert/SyAlert.stories.ts +19 -12
  93. package/src/components/SyAlert/SyAlert.vue +88 -51
  94. package/src/components/SyAlert/tests/SyAlert.spec.ts +20 -2
  95. package/src/components/SyAlert/tests/__snapshots__/SyAlert.spec.ts.snap +83 -75
  96. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +56 -0
  97. package/src/components/UserMenuBtn/UserMenuBtn.vue +4 -2
  98. package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +41 -0
  99. package/src/components/index.ts +2 -0
  100. package/src/composables/date/useDateFormat.ts +17 -1
  101. package/src/composables/date/useDateFormatDayjs.ts +84 -0
  102. package/src/composables/date/useDateInitializationDayjs.ts +133 -0
  103. package/src/composables/rules/useFieldValidation.ts +26 -3
  104. package/src/stories/Accessibilite/Avancement/Avancement.mdx +12 -0
  105. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +134 -0
  106. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +1 -1
  107. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +31 -2
  108. package/src/components/LangBtn/tests/Config.spec.ts +0 -24
@@ -2,86 +2,94 @@
2
2
 
3
3
  exports[`Alert > render correctly 1`] = `
4
4
  <div
5
- class="
6
- alert
7
- alert--success
8
- text-success
9
- v-alert
10
- v-alert--border
11
- v-alert--border-start
12
- v-alert--density-default
13
- v-alert--variant-tonal
14
- v-theme--light
15
- "
5
+ class="sy-alert"
16
6
  message="message"
17
7
  role="alert"
8
+ title="title"
18
9
  >
19
- <!---->
20
- <span class="v-alert__underlay"></span>
21
- <div class="v-alert__border"></div>
22
- <div class="v-alert__prepend">
23
- <i
24
- aria-hidden="true"
25
- class="
26
- 11.59L6
27
- 12
28
- 12
29
- 12
30
- 12
31
- 12
32
- 12
33
- 12S6.5
34
- 12S7.59
35
- 13L10
36
- 14.17L7.41
37
- 16.41
38
- 16.41
39
- 17.5
40
- 17.5
41
- 17L18
42
- 2
43
- 2
44
- 2
45
- 2
46
- 20
47
- 20
48
- 20
49
- 20
50
- 20C7.59
51
- 20M16.59
52
- 22
53
- 22
54
- 22
55
- 22
56
- 2C6.5
57
- 2M12
58
- 4
59
- 4
60
- 4
61
- 4
62
- 6.5
63
- 7.58L10
64
- 7.58Z
65
- 7.59
66
- 9L16.59
67
- M12
68
- alert-icon
69
- mdi
70
- notranslate
71
- v-icon
72
- v-theme--light
73
- "
74
- style="font-size: 1.5rem; height: 1.5rem; width: 1.5rem;"
75
- ></i>
76
- </div>
77
- <div class="v-alert__content">
78
- <div class="v-alert-title">
79
- title
10
+ <div
11
+ class="
12
+ alert
13
+ alert--success
14
+ text-success
15
+ v-alert
16
+ v-alert--border
17
+ v-alert--border-start
18
+ v-alert--density-default
19
+ v-alert--variant-tonal
20
+ v-theme--light
21
+ "
22
+ message="message"
23
+ role="alert"
24
+ >
25
+ <!---->
26
+ <span class="v-alert__underlay"></span>
27
+ <div class="v-alert__border"></div>
28
+ <div class="v-alert__prepend">
29
+ <i
30
+ aria-hidden="true"
31
+ class="
32
+ 11.59L6
33
+ 12
34
+ 12
35
+ 12
36
+ 12
37
+ 12
38
+ 12
39
+ 12S6.5
40
+ 12S7.59
41
+ 13L10
42
+ 14.17L7.41
43
+ 16.41
44
+ 16.41
45
+ 17.5
46
+ 17.5
47
+ 17L18
48
+ 2
49
+ 2
50
+ 2
51
+ 2
52
+ 20
53
+ 20
54
+ 20
55
+ 20
56
+ 20C7.59
57
+ 20M16.59
58
+ 22
59
+ 22
60
+ 22
61
+ 22
62
+ 2C6.5
63
+ 2M12
64
+ 4
65
+ 4
66
+ 4
67
+ 4
68
+ 6.5
69
+ 7.58L10
70
+ 7.58Z
71
+ 7.59
72
+ 9L16.59
73
+ M12
74
+ alert-icon
75
+ mdi
76
+ notranslate
77
+ v-icon
78
+ v-theme--light
79
+ "
80
+ role="presentation"
81
+ style="font-size: 1.5rem; height: 1.5rem; width: 1.5rem;"
82
+ ></i>
80
83
  </div>
84
+ <div class="v-alert__content">
85
+ <div class="v-alert-title">
86
+ title
87
+ </div>
88
+ <!---->
89
+ slot content
90
+ </div>
91
+ <!---->
81
92
  <!---->
82
- slot content
83
93
  </div>
84
- <!---->
85
- <!---->
86
94
  </div>
87
95
  `;
@@ -44,6 +44,13 @@ const meta = {
44
44
  type: { summary: 'string' },
45
45
  },
46
46
  },
47
+ 'logoutText': {
48
+ control: 'text',
49
+ description: 'Texte dans le bouton de déconnexion',
50
+ table: {
51
+ type: { summary: 'string' },
52
+ },
53
+ },
47
54
  'additionalInformation': {
48
55
  control: 'text',
49
56
  description: 'Informations supplémentaires sur l\'utilisateur (ex: rôle, service, etc.)',
@@ -376,6 +383,55 @@ export const CustomFullName: Story = {
376
383
  },
377
384
  }
378
385
 
386
+ export const CustomLogoutText: Story = {
387
+ parameters: {
388
+ sourceCode: [
389
+ {
390
+ name: 'Template',
391
+ code: `<template>
392
+ <UserMenuBtn
393
+ v-model="selected"
394
+ :menu-items="menuItems"
395
+ :logout-text="Déconnexion"
396
+ />
397
+ </template>`,
398
+ },
399
+ {
400
+ name: 'Script',
401
+ code: `<script setup lang="ts">
402
+ import { ref } from 'vue'
403
+ import { UserMenuBtn } from '@cnamts/synapse'
404
+
405
+ const selected = ref(null)
406
+ const menuItems = ref([
407
+ { text: 'Administration', value: 'Administration' },
408
+ { text: 'Profil', value: 'Profil' },
409
+ { text: 'Paramètres', value: 'Paramètres' },
410
+ ])
411
+
412
+ const logoutText = ref('Déconnexion')
413
+ </script>`,
414
+ },
415
+ ],
416
+ },
417
+ args: {
418
+ ...Default.args,
419
+ logoutText: 'Déconnexion',
420
+ },
421
+ render: (args) => {
422
+ return {
423
+ components: { UserMenuBtn },
424
+ setup() {
425
+ return { args }
426
+ },
427
+ template: `
428
+ <div class="pa-4">
429
+ <UserMenuBtn v-bind="args"/>
430
+ </div>`,
431
+ }
432
+ },
433
+ }
434
+
379
435
  export const CustomAdditionalInformation: Story = {
380
436
  parameters: {
381
437
  sourceCode: [
@@ -15,6 +15,7 @@
15
15
  hideLogoutBtn?: boolean
16
16
  isMobileView?: boolean
17
17
  hideUserIcon?: boolean
18
+ logoutText?: string
18
19
  }>(), {
19
20
  menuItems: () => [],
20
21
  additionalInformation: 'Information supplémentaire',
@@ -22,6 +23,7 @@
22
23
  hideLogoutBtn: false,
23
24
  isMobileView: false,
24
25
  hideUserIcon: false,
26
+ logoutText: 'Logout',
25
27
  })
26
28
 
27
29
  const modelValue = defineModel<MenuItem | null>({
@@ -74,8 +76,8 @@
74
76
  class="mr-4"
75
77
  v-bind="options['logoutIcon']"
76
78
  />
77
- <VListItemTitle>
78
- Logout
79
+ <VListItemTitle class="logout">
80
+ {{ props.logoutText }}
79
81
  </VListItemTitle>
80
82
  </div>
81
83
  </VListItem>
@@ -122,4 +122,45 @@ describe('UserMenuBtn', () => {
122
122
  expect(wrapper.emitted('update:modelValue')).toBeTruthy()
123
123
  expect(wrapper.emitted('update:modelValue')![0]).toEqual(['test-value'])
124
124
  })
125
+
126
+ it('possède la prop logoutText custom', async () => {
127
+ const customLogoutText = 'Déconnexion'
128
+ const wrapper = mount(UserMenuBtn, {
129
+ global: {
130
+ plugins: [vuetify],
131
+ },
132
+ props: {
133
+ modelValue: null,
134
+ logoutText: customLogoutText,
135
+ hideLogoutBtn: false,
136
+ menuItems: [{ text: 'Item 1', value: 'item1' }],
137
+ fullName: 'John Doe',
138
+ isMobileView: false,
139
+ hideUserIcon: false,
140
+ },
141
+ })
142
+
143
+ // Vérifier directement que la prop est correctement passée au composant
144
+ expect(wrapper.props('logoutText')).toBe(customLogoutText)
145
+ })
146
+
147
+ it('possède la prop logoutText par défaut', async () => {
148
+ const defaultLogoutText = 'Logout'
149
+ const wrapper = mount(UserMenuBtn, {
150
+ global: {
151
+ plugins: [vuetify],
152
+ },
153
+ props: {
154
+ modelValue: null,
155
+ hideLogoutBtn: false,
156
+ menuItems: [{ text: 'Item 1', value: 'item1' }],
157
+ fullName: 'John Doe',
158
+ isMobileView: false,
159
+ hideUserIcon: false,
160
+ },
161
+ })
162
+
163
+ // Vérifier directement que la prop est correctement passée au composant
164
+ expect(wrapper.props('logoutText')).toBe(defaultLogoutText)
165
+ })
125
166
  })
@@ -3,6 +3,7 @@ export { useFieldValidation } from '../composables/rules/useFieldValidation'
3
3
  export type { RuleOptions } from '../composables/rules/useFieldValidation'
4
4
  export { useNotificationService } from '../services/NotificationService'
5
5
  export { useValidation } from '../composables/validation/useValidation'
6
+ export { useDateFormat } from '../composables/date/useDateFormatDayjs'
6
7
  export { default as BackBtn } from './BackBtn/BackBtn.vue'
7
8
  export { default as BackToTopBtn } from './BackToTopBtn/BackToTopBtn.vue'
8
9
  export { default as ChipList } from './ChipList/ChipList.vue'
@@ -42,6 +43,7 @@ export { default as HeaderMenuBtn } from './HeaderBar/HeaderMenuBtn/HeaderMenuBt
42
43
  export { default as HeaderLoading } from './HeaderLoading/HeaderLoading.vue'
43
44
  export { default as HeaderNavigationBar } from './HeaderNavigationBar/HeaderNavigationBar.vue'
44
45
  export { default as HeaderToolbar } from './HeaderToolbar/HeaderToolbar.vue'
46
+ export { indicatifs } from './PhoneField/indicatifs'
45
47
  export { default as LangBtn } from './LangBtn/LangBtn.vue'
46
48
  export { default as Logo } from './Logo/Logo.vue'
47
49
  export { default as LogoBrandSection } from './LogoBrandSection/LogoBrandSection.vue'
@@ -8,9 +8,25 @@
8
8
  * @param format - Le format de la date (ex: 'DD/MM/YYYY')
9
9
  * @returns Un objet Date ou null si la chaîne n'est pas valide
10
10
  */
11
- export const parseDate = (dateString: string, format: string): Date | null => {
11
+ export const parseDate = (dateString: string | Date | null, format: string): Date | null => {
12
+ // Si dateString est null ou undefined, retourner null
12
13
  if (!dateString) return null
13
14
 
15
+ // Si dateString est déjà un objet Date, le retourner directement
16
+ if (dateString instanceof Date) {
17
+ return dateString
18
+ }
19
+
20
+ // Si dateString n'est pas une chaîne de caractères, convertir en chaîne ou retourner null
21
+ if (typeof dateString !== 'string') {
22
+ try {
23
+ dateString = String(dateString)
24
+ }
25
+ catch {
26
+ return null
27
+ }
28
+ }
29
+
14
30
  // Créer un mapping des positions des éléments de date selon le format
15
31
  const separator = format.includes('/') ? '/' : format.includes('-') ? '-' : '.'
16
32
  const parts = format.split(separator)
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Composable pour le formatage et le parsing des dates avec dayjs
3
+ */
4
+ import dayjs from 'dayjs'
5
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
6
+ import localizedFormat from 'dayjs/plugin/localizedFormat'
7
+ import utc from 'dayjs/plugin/utc'
8
+ import timezone from 'dayjs/plugin/timezone'
9
+ import 'dayjs/locale/fr'
10
+
11
+ // Initialiser les plugins dayjs
12
+ dayjs.extend(customParseFormat)
13
+ dayjs.extend(localizedFormat)
14
+ dayjs.extend(utc)
15
+ dayjs.extend(timezone)
16
+ dayjs.locale('fr')
17
+
18
+ /**
19
+ * Parse une chaîne de caractères en objet Date selon un format spécifié
20
+ * @param dateString - La chaîne de caractères à parser
21
+ * @param format - Le format de la date (ex: 'DD/MM/YYYY')
22
+ * @returns Un objet Date ou null si la chaîne n'est pas valide
23
+ */
24
+ export const parseDate = (dateString: string | Date | null, format: string): Date | null => {
25
+ // Si dateString est null ou undefined, retourner null
26
+ if (!dateString) return null
27
+
28
+ // Si dateString est déjà un objet Date, le retourner directement
29
+ if (dateString instanceof Date) {
30
+ return dateString
31
+ }
32
+
33
+ // Si dateString n'est pas une chaîne de caractères, convertir en chaîne ou retourner null
34
+ if (typeof dateString !== 'string') {
35
+ try {
36
+ dateString = String(dateString)
37
+ }
38
+ catch {
39
+ return null
40
+ }
41
+ }
42
+
43
+ // Utiliser dayjs pour parser la date
44
+ const parsedDate = dayjs(dateString, format, true)
45
+
46
+ if (!parsedDate.isValid()) return null
47
+
48
+ // Extraire les composants de la date pour créer une date UTC
49
+ // Cela évite les problèmes de décalage de fuseau horaire
50
+ return dayjs.utc()
51
+ .year(parsedDate.year())
52
+ .month(parsedDate.month())
53
+ .date(parsedDate.date())
54
+ .hour(0)
55
+ .minute(0)
56
+ .second(0)
57
+ .millisecond(0)
58
+ .toDate()
59
+ }
60
+
61
+ /**
62
+ * Formate une date selon un format spécifié
63
+ * @param date - La date à formater
64
+ * @param format - Le format de sortie (ex: 'DD/MM/YYYY')
65
+ * @returns La date formatée en chaîne de caractères
66
+ */
67
+ export const formatDate = (date: Date | null, format: string): string => {
68
+ if (!date) return ''
69
+
70
+ return dayjs(date).format(format)
71
+ }
72
+
73
+ /**
74
+ * Hook composable pour le formatage et le parsing des dates
75
+ * @returns Fonctions de formatage et parsing de dates
76
+ */
77
+ export function useDateFormat() {
78
+ return {
79
+ parseDate,
80
+ formatDate,
81
+ }
82
+ }
83
+
84
+ export default useDateFormat
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Composable pour l'initialisation des dates dans le DatePicker avec dayjs
3
+ */
4
+ import dayjs from 'dayjs'
5
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
6
+ import utc from 'dayjs/plugin/utc'
7
+ import timezone from 'dayjs/plugin/timezone'
8
+ import 'dayjs/locale/fr'
9
+
10
+ // Initialiser les plugins dayjs
11
+ dayjs.extend(customParseFormat)
12
+ dayjs.extend(utc)
13
+ dayjs.extend(timezone)
14
+ dayjs.locale('fr')
15
+
16
+ // Types
17
+ export type DateValue = string | [string, string] | null
18
+ export type DateInput = string | string[] | null | object
19
+
20
+ /**
21
+ * Parse une date en utilisant dayjs et retourne une Date UTC
22
+ * @param dateStr - La chaîne de date à analyser
23
+ * @param format - Le format de la date
24
+ * @returns Une Date ou null si la date est invalide
25
+ */
26
+ const parseToUTCDate = (dateStr: string, format: string): Date | null => {
27
+ if (!dayjs(dateStr, format).isValid()) return null
28
+
29
+ // Extraire les composants de la date à partir de la chaîne
30
+ const dateParts = dayjs(dateStr, format)
31
+
32
+ // Créer une date UTC avec les composants exacts pour éviter les décalages de fuseau horaire
33
+ // Utiliser set pour définir explicitement l'année, le mois et le jour
34
+ return dayjs.utc()
35
+ .year(dateParts.year())
36
+ .month(dateParts.month())
37
+ .date(dateParts.date())
38
+ .hour(0)
39
+ .minute(0)
40
+ .second(0)
41
+ .millisecond(0)
42
+ .toDate()
43
+ }
44
+
45
+ /**
46
+ * Initialise les dates sélectionnées à partir d'une valeur d'entrée
47
+ * @param modelValue - La valeur d'entrée (peut être une chaîne, un tableau, null ou un objet)
48
+ * @param displayFormat - Le format d'affichage des dates
49
+ * @param returnFormat - Le format de retour des dates (optionnel)
50
+ * @returns Une date, un tableau de dates ou null
51
+ */
52
+ export const initializeSelectedDates = (
53
+ modelValue: DateInput | null,
54
+ displayFormat: string,
55
+ returnFormat: string = '',
56
+ ): Date | Date[] | null => {
57
+ if (!modelValue) return null
58
+
59
+ // Déterminer le format à utiliser pour l'analyse
60
+ const parseFormat = returnFormat || displayFormat
61
+
62
+ if (Array.isArray(modelValue)) {
63
+ if (modelValue.length >= 2) {
64
+ // Essayer d'abord avec le format de retour, puis avec le format d'affichage
65
+ let dates = [
66
+ parseToUTCDate(modelValue[0], parseFormat),
67
+ parseToUTCDate(modelValue[1], parseFormat),
68
+ ]
69
+
70
+ // Si l'une des dates est invalide avec le format de retour, essayer avec le format d'affichage
71
+ if (dates.some(date => date === null) && returnFormat) {
72
+ dates = [
73
+ parseToUTCDate(modelValue[0], displayFormat),
74
+ parseToUTCDate(modelValue[1], displayFormat),
75
+ ]
76
+ }
77
+
78
+ // Vérifie si l'une des dates est toujours invalide
79
+ if (dates.some(date => date === null)) {
80
+ return []
81
+ }
82
+
83
+ // Vérifie si la première date est après la seconde
84
+ if (dates[0] && dates[1] && dayjs(dates[0]).isAfter(dayjs(dates[1]))) {
85
+ return []
86
+ }
87
+
88
+ // Filtrer les dates nulles et convertir en tableau de Date
89
+ return dates.filter((date): date is Date => date !== null)
90
+ }
91
+
92
+ if (modelValue.length === 1) {
93
+ // Essayer d'abord avec le format de retour, puis avec le format d'affichage
94
+ let date = parseToUTCDate(modelValue[0], parseFormat)
95
+
96
+ // Si la date est invalide avec le format de retour, essayer avec le format d'affichage
97
+ if (date === null && returnFormat) {
98
+ date = parseToUTCDate(modelValue[0], displayFormat)
99
+ }
100
+
101
+ return date === null ? [] : [date]
102
+ }
103
+
104
+ return []
105
+ }
106
+
107
+ // Si modelValue est un objet, on le convertit en chaîne
108
+ if (typeof modelValue === 'object') {
109
+ return null
110
+ }
111
+
112
+ // Essayer d'abord avec le format de retour, puis avec le format d'affichage
113
+ let date = parseToUTCDate(modelValue, parseFormat)
114
+
115
+ // Si la date est invalide avec le format de retour, essayer avec le format d'affichage
116
+ if (date === null && returnFormat) {
117
+ date = parseToUTCDate(modelValue, displayFormat)
118
+ }
119
+
120
+ return date
121
+ }
122
+
123
+ /**
124
+ * Hook composable pour l'initialisation des dates
125
+ * @returns Fonction d'initialisation des dates
126
+ */
127
+ export function useDateInitialization() {
128
+ return {
129
+ initializeSelectedDates,
130
+ }
131
+ }
132
+
133
+ export default useDateInitialization
@@ -177,16 +177,30 @@ export function useFieldValidation() {
177
177
 
178
178
  case 'notBeforeToday': {
179
179
  const dateValue = new Date(value)
180
+ // Réinitialiser l'heure à minuit pour ne comparer que les dates
181
+ dateValue.setHours(0, 0, 0, 0)
182
+
183
+ // Créer une date aujourd'hui à minuit pour comparaison
184
+ const today = new Date()
185
+ today.setHours(0, 0, 0, 0)
186
+
180
187
  return createValidationResult(
181
- dateValue >= new Date(),
188
+ dateValue >= today,
182
189
  options.message || options.warningMessage || `${identifier} ne peut pas être antérieur à aujourd'hui.`,
183
190
  )
184
191
  }
185
192
 
186
193
  case 'notAfterToday': {
187
194
  const dateValue = new Date(value)
195
+ // Réinitialiser l'heure à minuit pour ne comparer que les dates
196
+ dateValue.setHours(0, 0, 0, 0)
197
+
198
+ // Créer une date aujourd'hui à minuit pour comparaison
199
+ const today = new Date()
200
+ today.setHours(0, 0, 0, 0)
201
+
188
202
  return createValidationResult(
189
- dateValue <= new Date(),
203
+ dateValue <= today,
190
204
  options.message || options.warningMessage || `${identifier} ne peut pas être postérieur à aujourd'hui.`,
191
205
  )
192
206
  }
@@ -262,8 +276,17 @@ export function useFieldValidation() {
262
276
  return { error: 'Date de référence invalide' }
263
277
  }
264
278
 
279
+ // Normaliser les deux dates en réinitialisant les heures/minutes/secondes
280
+ dateValue.setHours(0, 0, 0, 0)
281
+ referenceDate.setHours(0, 0, 0, 0)
282
+
283
+ // Comparer les dates normalisées
284
+ const isSameDate = dateValue.getFullYear() === referenceDate.getFullYear()
285
+ && dateValue.getMonth() === referenceDate.getMonth()
286
+ && dateValue.getDate() === referenceDate.getDate()
287
+
265
288
  return createValidationResult(
266
- dateValue.getTime() === referenceDate.getTime(),
289
+ isSameDate,
267
290
  options.message || options.warningMessage || `${identifier} doit être exactement le ${options.date}.`,
268
291
  )
269
292
  }
@@ -0,0 +1,12 @@
1
+ import { Story, Meta } from '@storybook/addon-docs/blocks';
2
+ import * as AvancementStories from './Avancement.stories.ts';
3
+
4
+ <Meta of={AvancementStories} />
5
+
6
+ # Outils de pré-audit
7
+
8
+ <Story of={AvancementStories.PreAudit} />
9
+
10
+ # Contrôle manuel
11
+
12
+ <Story of={AvancementStories.Manuel} />