@colisweb/rescript-toolkit 5.26.1 → 5.27.0

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/locale/fr.json CHANGED
@@ -1,4 +1,9 @@
1
1
  [
2
+ {
3
+ "id": "_0195a359",
4
+ "defaultMessage": "Au moins 1 majuscule",
5
+ "message": "Au moins 1 majuscule"
6
+ },
2
7
  {
3
8
  "id": "_0475def8",
4
9
  "defaultMessage": "Fin",
@@ -19,6 +24,11 @@
19
24
  "defaultMessage": "Mardi",
20
25
  "message": "Mardi"
21
26
  },
27
+ {
28
+ "id": "_10b714f3",
29
+ "defaultMessage": "Au moins 10 caractères",
30
+ "message": "Au moins 10 caractères"
31
+ },
22
32
  {
23
33
  "id": "_1484eaf0",
24
34
  "defaultMessage": "Format requis : 14 chiffres",
@@ -54,6 +64,11 @@
54
64
  "defaultMessage": "Jeudi",
55
65
  "message": "Jeudi"
56
66
  },
67
+ {
68
+ "id": "_356c2591",
69
+ "defaultMessage": "Au moins 1 minuscule",
70
+ "message": "Au moins 1 minuscule"
71
+ },
57
72
  {
58
73
  "id": "_435887be",
59
74
  "defaultMessage": "Seulement",
@@ -104,6 +119,11 @@
104
119
  "defaultMessage": "Une erreur est survenue lors de la recherche",
105
120
  "message": "Une erreur est survenue lors de la recherche"
106
121
  },
122
+ {
123
+ "id": "_6f6118f7",
124
+ "defaultMessage": "Votre mot de passe ne doit pas contenir :",
125
+ "message": "Votre mot de passe ne doit pas contenir :"
126
+ },
107
127
  {
108
128
  "id": "_703b9075",
109
129
  "defaultMessage": "Valeur non valide.",
@@ -144,6 +164,11 @@
144
164
  "defaultMessage": "Doit être un entier positif",
145
165
  "message": "Doit être un entier positif"
146
166
  },
167
+ {
168
+ "id": "_8b33a5ae",
169
+ "defaultMessage": "Votre identifiant",
170
+ "message": "Votre identifiant"
171
+ },
147
172
  {
148
173
  "id": "_8f8eb0df",
149
174
  "defaultMessage": "Vendredi",
@@ -219,6 +244,11 @@
219
244
  "defaultMessage": "Mauvais format (req: {exemple})",
220
245
  "message": "Mauvais format (req: {exemple})"
221
246
  },
247
+ {
248
+ "id": "_d4abc929",
249
+ "defaultMessage": "Le mot de passe doit contenir :",
250
+ "message": "Le mot de passe doit contenir :"
251
+ },
222
252
  {
223
253
  "id": "_d56f025d",
224
254
  "defaultMessage": "Champs requis",
@@ -254,6 +284,11 @@
254
284
  "defaultMessage": "Nbr colis",
255
285
  "message": "Nbr colis"
256
286
  },
287
+ {
288
+ "id": "_f1737662",
289
+ "defaultMessage": "Au moins 1 chiffre",
290
+ "message": "Au moins 1 chiffre"
291
+ },
257
292
  {
258
293
  "id": "clipboard.copied",
259
294
  "defaultMessage": "Copied to clipboard",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "5.26.1",
3
+ "version": "5.27.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "clean": "rescript clean",
@@ -71,7 +71,11 @@ module Make = (Lenses: Lenses) => {
71
71
  }): t
72
72
  | True({field: Lenses.field<bool>, error: option<string>}): t
73
73
  | False({field: Lenses.field<bool>, error: option<string>}): t
74
- | OptionNonEmpty({field: Lenses.field<option<'a>>, error: option<string>}): t
74
+ | OptionNonEmpty({
75
+ field: Lenses.field<option<'a>>,
76
+ optionalPredicate?: Lenses.state => bool,
77
+ error: option<string>,
78
+ }): t
75
79
  | ArrayNonEmpty({field: Lenses.field<array<'a>>, error: option<string>}): t
76
80
 
77
81
  type schema = array<t>
@@ -96,7 +100,9 @@ module Make = (Lenses: Lenses) => {
96
100
  [CustomNestedSchema2({field, predicate})]
97
101
  }
98
102
 
99
- let optionNonEmpty = (~error=?, field) => [OptionNonEmpty({field, error})]
103
+ let optionNonEmpty = (~error=?, ~optionalPredicate=?, field) => [
104
+ OptionNonEmpty({field, ?optionalPredicate, error}),
105
+ ]
100
106
 
101
107
  let arrayNonEmpty = (~error=?, field) => [ArrayNonEmpty({field, error})]
102
108
 
@@ -359,14 +365,16 @@ module Make = (Lenses: Lenses) => {
359
365
 
360
366
  (Field(field), NestedErrors2(results))
361
367
  }
362
- | Validation.OptionNonEmpty({field, error}) => {
368
+ | Validation.OptionNonEmpty({field, error} as props) => {
363
369
  let value = Lenses.get(values, field)
364
370
 
365
371
  (
366
372
  Field(field),
367
- value->Option.isNone
368
- ? Error(error->Belt.Option.getWithDefault(i18n.stringNonEmpty(~value="")))
369
- : Valid,
373
+ switch value {
374
+ | _ if props.optionalPredicate->Option.mapWithDefault(false, fn => fn(values)) => Valid
375
+ | None => Error(error->Belt.Option.getWithDefault(i18n.stringNonEmpty(~value="")))
376
+ | Some(_) => Valid
377
+ },
370
378
  )
371
379
  }
372
380
  | Validation.ArrayNonEmpty({field, error}) => {
@@ -43,3 +43,4 @@ module WeekdayNavigation = Toolkit__Ui_WeekdayNavigation
43
43
  module Popover = Toolkit__Ui_Popover
44
44
  module DropdownMenu = Toolkit__Ui_DropdownMenu
45
45
  module ScrollArea = Toolkit__Ui_ScrollArea
46
+ module PasswordRulesNotice = Toolkit__Ui_PasswordRulesNotice
@@ -0,0 +1,75 @@
1
+ open ReactIntl
2
+
3
+ module PasswordHint = {
4
+ @react.component
5
+ let make = (~isValid, ~children) => {
6
+ <div
7
+ className={cx([
8
+ "flex flex-row gap-1 items-center transition-colors duration-150 ease-in",
9
+ isValid ? "text-success-700 font-semibold" : "",
10
+ ])}>
11
+ <ReactIcons.MdCheckCircle
12
+ className={cx([
13
+ "transition-colors duration-150 ease-in",
14
+ isValid ? "text-success-700" : "text-info-400",
15
+ ])}
16
+ />
17
+ children
18
+ </div>
19
+ }
20
+ }
21
+ @react.component
22
+ let make = (~login=?, ~password) => {
23
+ let passwordHasEnoughCharacters = password->Js.String2.length >= 10
24
+ let passwordHasMinusCharacter = React.useMemo(
25
+ () => {Js.Re.test_(%re("/(?=.*[a-z])./"), password)},
26
+ [password],
27
+ )
28
+ let passwordHasUpperCharacter = React.useMemo(
29
+ () => Js.Re.test_(%re("/(?=.*[A-Z])./"), password),
30
+ [password],
31
+ )
32
+ let passwordHasDigit = React.useMemo(() => Js.Re.test_(%re("/(?=.*\d)./"), password), [password])
33
+
34
+ <div
35
+ className="bg-info-50 rounded-lg p-2 flex flex-row items-center gap-2 border border-info-600">
36
+ <ReactIcons.FaInfoCircle size={30} className="text-info-600 mr-2" />
37
+ <div className="text-info-600">
38
+ <p className="mb-2 font-semibold">
39
+ <FormattedMessage defaultMessage={"Le mot de passe doit contenir :"} />
40
+ </p>
41
+ <div className="grid grid-cols-2 text-sm gap-2">
42
+ <PasswordHint isValid={passwordHasEnoughCharacters}>
43
+ <FormattedMessage defaultMessage={"Au moins 10 caractères"} />
44
+ </PasswordHint>
45
+ <PasswordHint isValid={passwordHasMinusCharacter}>
46
+ <FormattedMessage defaultMessage={"Au moins 1 minuscule"} />
47
+ </PasswordHint>
48
+ <PasswordHint isValid={passwordHasDigit}>
49
+ <FormattedMessage defaultMessage={"Au moins 1 chiffre"} />
50
+ </PasswordHint>
51
+ <PasswordHint isValid={passwordHasUpperCharacter}>
52
+ <FormattedMessage defaultMessage={"Au moins 1 majuscule"} />
53
+ </PasswordHint>
54
+ </div>
55
+ {login->Option.mapWithDefault(React.null, login => {
56
+ let passwordDontContainLogin = !(
57
+ password
58
+ ->Js.String2.toLowerCase
59
+ ->Js.String2.includes(login->Js.String2.toLowerCase)
60
+ )
61
+
62
+ <>
63
+ <p className="mt-4 mb-2 font-semibold">
64
+ <FormattedMessage defaultMessage={"Votre mot de passe ne doit pas contenir :"} />
65
+ </p>
66
+ <div className="grid grid-cols-2 text-sm gap-2">
67
+ <PasswordHint isValid={passwordDontContainLogin && password !== ""}>
68
+ <FormattedMessage defaultMessage={"Votre identifiant"} />
69
+ </PasswordHint>
70
+ </div>
71
+ </>
72
+ })}
73
+ </div>
74
+ </div>
75
+ }