cozy-ui-plus 3.1.2 → 4.1.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/AppSections/Sections.js +5 -7
  3. package/dist/AppSections/components/AppsSection.js +2 -2
  4. package/dist/AppTile/index.js +3 -3
  5. package/dist/Contacts/AddModal/ContactAddressDialog/index.js +4 -4
  6. package/dist/Contacts/AddModal/ContactForm/FieldInput.js +6 -10
  7. package/dist/Contacts/AddModal/ContactForm/FieldInputAccordion.js +4 -4
  8. package/dist/Contacts/AddModal/ContactForm/FieldInputArray.js +7 -9
  9. package/dist/Contacts/AddModal/ContactForm/FieldInputLayout.js +6 -8
  10. package/dist/Contacts/AddModal/ContactForm/FieldInputWrapper.js +1 -1
  11. package/dist/Contacts/AddModal/ContactForm/TextFieldCustomLabelSelect.js +3 -3
  12. package/dist/Contacts/AddModal/ContactForm/TextFieldSelect.js +4 -4
  13. package/dist/Contacts/AddModal/ContactForm/helpers.js +90 -33
  14. package/dist/Contacts/AddModal/ContactForm/index.js +10 -5
  15. package/dist/Contacts/AddModal/ContactForm/locales/index.js +4 -4
  16. package/dist/Contacts/AddModal/CustomLabelDialog/index.js +4 -4
  17. package/dist/Contacts/AddModal/index.js +4 -4
  18. package/dist/Contacts/GroupsSelect/GroupCreation.js +3 -3
  19. package/dist/Contacts/GroupsSelect/GroupsSelectProvider.js +3 -3
  20. package/dist/Contacts/GroupsSelect/SelectBox/Control.js +4 -4
  21. package/dist/Contacts/GroupsSelect/useGroupSelect.js +4 -4
  22. package/dist/Contacts/Header/GroupsSelection.js +4 -4
  23. package/dist/Contacts/Header/ImportDropdown.js +4 -4
  24. package/dist/Contacts/Header/index.js +4 -4
  25. package/dist/ContactsList/Contacts/ContactIdentity.js +4 -4
  26. package/dist/ContactsList/ContactsList.js +3 -3
  27. package/dist/ContactsList/locales/withContactsListLocales.js +2 -4
  28. package/dist/ContactsListModal/ContactsListContent.js +3 -3
  29. package/dist/ContactsListModal/ContactsListModal.js +3 -3
  30. package/dist/ContactsListModal/withContactsListLocales.js +2 -4
  31. package/dist/Dialogs/AuthentificationDialog/index.js +2 -2
  32. package/dist/Dialogs/AuthentificationDialog/withSpecificDialogsLocales.js +2 -4
  33. package/dist/FilePicker/FilePickerBodyItem.js +3 -3
  34. package/dist/FilePicker/FilePickerFooter.js +3 -3
  35. package/dist/FilePicker/docs/DemoProvider.js +3 -3
  36. package/dist/ListItem/ExpandedAttributes/ExpandedAttribute.js +3 -3
  37. package/dist/ListItem/ExpandedAttributes/index.js +3 -3
  38. package/dist/ListItem/ListItemBase/Renaming/RenameDialog.js +3 -3
  39. package/dist/ListItem/ListItemFile/ExpirationAnnotation.js +3 -3
  40. package/dist/ListItem/ListItemFile/SecondaryText.js +3 -3
  41. package/dist/ListItem/hoc/withListItemLocales.js +2 -4
  42. package/dist/Paywall/Paywall.js +3 -3
  43. package/dist/Paywall/locales/withPaywallLocales.js +2 -4
  44. package/dist/Qualification/QualificationGrid/index.js +3 -3
  45. package/dist/Qualification/QualificationGrid/locales/withLocales.js +2 -4
  46. package/dist/Qualification/QualificationModal/index.js +4 -4
  47. package/dist/Storage/StorageButton.js +4 -4
  48. package/dist/Storage/StorageProgress.js +4 -4
  49. package/dist/UploadQueue/Item.js +3 -3
  50. package/dist/UploadQueue/Pending.js +3 -3
  51. package/dist/UploadQueue/RemainingTime.js +3 -3
  52. package/dist/UploadQueue/index.js +4 -6
  53. package/dist/src/Contacts/AddModal/ContactForm/FieldInput.d.ts +2 -6
  54. package/dist/src/Contacts/AddModal/ContactForm/FieldInputArray.d.ts +2 -6
  55. package/dist/src/Contacts/AddModal/ContactForm/helpers.d.ts +4 -2
  56. package/dist/test/I18n.d.ts +1 -1
  57. package/package.json +7 -5
  58. package/src/AppSections/Readme.md +1 -1
  59. package/src/AppSections/Sections.jsx +1 -2
  60. package/src/AppSections/components/AppsSection.jsx +1 -1
  61. package/src/AppSections/helpers.spec.js +1 -1
  62. package/src/AppTile/AppTile.spec.jsx +1 -2
  63. package/src/AppTile/Readme.md +1 -1
  64. package/src/AppTile/index.jsx +1 -1
  65. package/src/Contacts/AddModal/ContactAddressDialog/index.jsx +1 -1
  66. package/src/Contacts/AddModal/ContactForm/FieldInput.jsx +4 -9
  67. package/src/Contacts/AddModal/ContactForm/FieldInputAccordion.jsx +1 -1
  68. package/src/Contacts/AddModal/ContactForm/FieldInputArray.jsx +8 -5
  69. package/src/Contacts/AddModal/ContactForm/FieldInputLayout.jsx +4 -4
  70. package/src/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx +1 -1
  71. package/src/Contacts/AddModal/ContactForm/TextFieldCustomLabelSelect.jsx +1 -2
  72. package/src/Contacts/AddModal/ContactForm/TextFieldSelect.jsx +1 -1
  73. package/src/Contacts/AddModal/ContactForm/helpers.js +65 -17
  74. package/src/Contacts/AddModal/ContactForm/helpers.spec.js +344 -1
  75. package/src/Contacts/AddModal/ContactForm/index.jsx +11 -6
  76. package/src/Contacts/AddModal/ContactForm/locales/en.json +1 -1
  77. package/src/Contacts/AddModal/ContactForm/locales/fr.json +1 -1
  78. package/src/Contacts/AddModal/ContactForm/locales/ru.json +1 -1
  79. package/src/Contacts/AddModal/ContactForm/locales/vi.json +1 -1
  80. package/src/Contacts/AddModal/CustomLabelDialog/index.jsx +1 -1
  81. package/src/Contacts/AddModal/index.jsx +1 -1
  82. package/src/Contacts/GroupsSelect/GroupCreation.jsx +1 -1
  83. package/src/Contacts/GroupsSelect/GroupsSelectProvider.jsx +1 -2
  84. package/src/Contacts/GroupsSelect/SelectBox/Control.jsx +1 -1
  85. package/src/Contacts/GroupsSelect/useGroupSelect.jsx +1 -1
  86. package/src/Contacts/Header/GroupsSelection.jsx +1 -1
  87. package/src/Contacts/Header/ImportDropdown.jsx +1 -1
  88. package/src/Contacts/Header/index.jsx +1 -1
  89. package/src/ContactsList/Contacts/ContactIdentity.jsx +1 -1
  90. package/src/ContactsList/ContactsList.jsx +1 -1
  91. package/src/ContactsList/locales/withContactsListLocales.jsx +1 -1
  92. package/src/ContactsListModal/ContactsListContent.jsx +1 -1
  93. package/src/ContactsListModal/ContactsListModal.jsx +1 -1
  94. package/src/ContactsListModal/Readme.md +1 -1
  95. package/src/ContactsListModal/withContactsListLocales.jsx +1 -1
  96. package/src/Dialogs/AuthentificationDialog/index.jsx +1 -1
  97. package/src/Dialogs/AuthentificationDialog/withSpecificDialogsLocales.jsx +1 -1
  98. package/src/FilePicker/FilePickerBodyItem.jsx +1 -1
  99. package/src/FilePicker/FilePickerFooter.jsx +1 -1
  100. package/src/FilePicker/docs/DemoProvider.jsx +1 -1
  101. package/src/ListItem/ExpandedAttributes/ExpandedAttribute.jsx +1 -1
  102. package/src/ListItem/ExpandedAttributes/index.jsx +1 -1
  103. package/src/ListItem/ListItemBase/Renaming/RenameDialog.jsx +1 -1
  104. package/src/ListItem/ListItemFile/ExpirationAnnotation.jsx +1 -1
  105. package/src/ListItem/ListItemFile/SecondaryText.jsx +1 -1
  106. package/src/ListItem/hoc/withListItemLocales.jsx +1 -1
  107. package/src/Paywall/Paywall.jsx +1 -1
  108. package/src/Paywall/locales/withPaywallLocales.jsx +1 -1
  109. package/src/Qualification/QualificationGrid/index.jsx +1 -1
  110. package/src/Qualification/QualificationGrid/locales/withLocales.jsx +1 -1
  111. package/src/Qualification/QualificationModal/index.jsx +1 -1
  112. package/src/Storage/StorageButton.jsx +1 -1
  113. package/src/Storage/StorageProgress.jsx +1 -1
  114. package/src/UploadQueue/Item.jsx +1 -1
  115. package/src/UploadQueue/Pending.jsx +1 -1
  116. package/src/UploadQueue/RemainingTime.jsx +1 -1
  117. package/src/UploadQueue/index.jsx +1 -2
  118. package/src/UploadQueue/index.spec.jsx +48 -34
  119. package/test/I18n.js +1 -1
@@ -9,26 +9,63 @@ import { CONTACTS_DOCTYPE } from 'cozy-client/dist/models/contact'
9
9
 
10
10
  import contactToFormValues from './contactToFormValues'
11
11
 
12
- export const fieldsRequired = [
13
- 'givenName',
14
- 'familyName',
15
- 'email[0].email',
16
- 'cozy'
17
- ]
12
+ export const getFirstValueIfArray = values => {
13
+ return Object.keys(values).reduce((acc, key) => {
14
+ const val = values[key]
15
+ acc[key] = Array.isArray(val) ? val[0] : val
16
+ return acc
17
+ }, {})
18
+ }
18
19
 
19
20
  /**
20
- * Returns errors if all required fields are empty
21
+ * Returns true if all fields have no values
21
22
  * @param {object} values - Fields values
22
- * @param {func} t - Translation function
23
+ * @param {import('../types').Field[]} fields - Fields configuration
24
+ * @returns {boolean} True if all fields have no values
25
+ */
26
+ export const hasNoValues = (values, fields) => {
27
+ const _values = getFirstValueIfArray(values)
28
+
29
+ return fields.every(field => !get(_values, field.name))
30
+ }
31
+
32
+ /**
33
+ * Returns true if the input is required and the form is invalid
34
+ * @param {boolean} required - Whether the input is required
35
+ * @param {object} formProps - The form props
36
+ * @returns {boolean} True if the input is required and the form is invalid
37
+ */
38
+ export const makeIsRequiredError = (required, formProps) => {
39
+ const { valid, submitFailed } = formProps
40
+
41
+ return required && !valid && submitFailed
42
+ }
43
+
44
+ /**
45
+ * Returns errors for required fields that are empty
46
+ * @param {object} values - Fields values
47
+ * @param {import('../types').Field[]} fields - Fields configuration
48
+ * @param {Function} t - Translation function
23
49
  * @returns {object} Errors
24
50
  */
25
- export const validateFields = (values, t) => {
51
+ export const validateFields = (values, fields, t) => {
26
52
  const errors = {}
27
- if (fieldsRequired.every(field => !get(values, field))) {
28
- fieldsRequired.forEach(field => {
29
- errors[field] = t('Contacts.AddModal.ContactForm.fields.required')
30
- })
31
- }
53
+ const fieldsRequired = fields.filter(field => field.required)
54
+ const _values = getFirstValueIfArray(values)
55
+
56
+ fieldsRequired.forEach(field => {
57
+ if (!get(_values, field.name)) {
58
+ errors[field.name] =
59
+ field.layout === 'array'
60
+ ? [
61
+ {
62
+ [field.name]: t('Contacts.AddModal.ContactForm.fields.required')
63
+ }
64
+ ]
65
+ : t('Contacts.AddModal.ContactForm.fields.required')
66
+ }
67
+ })
68
+
32
69
  return errors
33
70
  }
34
71
 
@@ -384,9 +421,20 @@ export const makeFields = (customFields, defaultFields) => {
384
421
 
385
422
  const fields = [...defaultFields]
386
423
 
387
- customFields.map(customField => {
388
- if (customField.position) {
389
- fields.splice(customField.position, 0, customField)
424
+ customFields.forEach(customField => {
425
+ const defaultField = fields.find(field => field.name === customField.name)
426
+ const _field = defaultField || customField
427
+
428
+ if (defaultField) {
429
+ Object.assign(_field, customField)
430
+ }
431
+
432
+ if (_field.position) {
433
+ if (defaultField) {
434
+ const fieldIndex = fields.indexOf(defaultField)
435
+ fields.splice(fieldIndex, 1)
436
+ }
437
+ fields.splice(_field.position, 0, _field)
390
438
  }
391
439
  })
392
440
 
@@ -7,7 +7,10 @@ import {
7
7
  makeImppValues,
8
8
  makeCustomLabel,
9
9
  makeFields,
10
- makeInitialCustomValue
10
+ makeInitialCustomValue,
11
+ hasNoValues,
12
+ getFirstValueIfArray,
13
+ validateFields
11
14
  } from './helpers'
12
15
  import { locales } from './locales'
13
16
 
@@ -388,4 +391,344 @@ describe('makeFields', () => {
388
391
 
389
392
  expect(res).toStrictEqual(defaultFields)
390
393
  })
394
+
395
+ it('should replace default fields values by custom fields', () => {
396
+ const defaultFields = [
397
+ { name: 'firstname', type: 'text', layout: 'accordion' },
398
+ { name: 'lastname' }
399
+ ]
400
+ const customFields = [
401
+ { name: 'firstname', isSecondary: true, layout: 'array' }
402
+ ]
403
+
404
+ const res = makeFields(customFields, defaultFields)
405
+
406
+ expect(res).toStrictEqual([
407
+ { name: 'firstname', type: 'text', isSecondary: true, layout: 'array' },
408
+ { name: 'lastname' }
409
+ ])
410
+ })
411
+
412
+ it('should replace default fields values and add custom fields at custom position', () => {
413
+ const defaultFields = [
414
+ { name: 'firstname', type: 'text', layout: 'accordion' },
415
+ { name: 'lastname' }
416
+ ]
417
+ const customFields = [
418
+ { name: 'firstname', isSecondary: true, layout: 'array', position: 1 }
419
+ ]
420
+
421
+ const res = makeFields(customFields, defaultFields)
422
+
423
+ expect(res).toStrictEqual([
424
+ { name: 'lastname' },
425
+ {
426
+ name: 'firstname',
427
+ type: 'text',
428
+ isSecondary: true,
429
+ layout: 'array',
430
+ position: 1
431
+ }
432
+ ])
433
+ })
434
+ })
435
+
436
+ describe('hasNoValues', () => {
437
+ it('should return true when all fields have no values', () => {
438
+ const values = {}
439
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
440
+
441
+ const res = hasNoValues(values, fields)
442
+
443
+ expect(res).toBe(true)
444
+ })
445
+
446
+ it('should return true when all field values are undefined', () => {
447
+ const values = { firstname: undefined, lastname: undefined }
448
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
449
+
450
+ const res = hasNoValues(values, fields)
451
+
452
+ expect(res).toBe(true)
453
+ })
454
+
455
+ it('should return true when all field values are null', () => {
456
+ const values = { firstname: null, lastname: null }
457
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
458
+
459
+ const res = hasNoValues(values, fields)
460
+
461
+ expect(res).toBe(true)
462
+ })
463
+
464
+ it('should return true when all field values are empty strings', () => {
465
+ const values = { firstname: '', lastname: '' }
466
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
467
+
468
+ const res = hasNoValues(values, fields)
469
+
470
+ expect(res).toBe(true)
471
+ })
472
+
473
+ it('should return true when all field values are empty arrays', () => {
474
+ const values = { email: [], phone: [] }
475
+ const fields = [{ name: 'email' }, { name: 'phone' }]
476
+
477
+ const res = hasNoValues(values, fields)
478
+
479
+ expect(res).toBe(true)
480
+ })
481
+
482
+ it('should return false when at least one field has a value', () => {
483
+ const values = { firstname: 'John', lastname: undefined }
484
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
485
+
486
+ const res = hasNoValues(values, fields)
487
+
488
+ expect(res).toBe(false)
489
+ })
490
+
491
+ it('should return false when at least one field has a non-empty string', () => {
492
+ const values = { firstname: '', lastname: 'Doe' }
493
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
494
+
495
+ const res = hasNoValues(values, fields)
496
+
497
+ expect(res).toBe(false)
498
+ })
499
+
500
+ it('should return false when at least one field has a non-empty array', () => {
501
+ const values = { email: [{ address: 'john.doe@cozycloud.cc' }], phone: [] }
502
+ const fields = [{ name: 'email' }, { name: 'phone' }]
503
+
504
+ const res = hasNoValues(values, fields)
505
+
506
+ expect(res).toBe(false)
507
+ })
508
+
509
+ it('should return true for nested field paths with no values', () => {
510
+ const values = { phone: [{ number: undefined }] }
511
+ const fields = [{ name: 'phone[0].number' }]
512
+
513
+ const res = hasNoValues(values, fields)
514
+
515
+ expect(res).toBe(true)
516
+ })
517
+
518
+ it('should handle mixed array and non-array values', () => {
519
+ const values = { firstname: 'John', lastname: ['Doe'] }
520
+ const fields = [{ name: 'firstname' }, { name: 'lastname' }]
521
+
522
+ const res = hasNoValues(values, fields)
523
+
524
+ expect(res).toBe(false)
525
+ })
526
+
527
+ it('should return true when fields array is empty', () => {
528
+ const values = { firstname: 'John', lastname: 'Doe' }
529
+ const fields = []
530
+
531
+ const res = hasNoValues(values, fields)
532
+
533
+ expect(res).toBe(true)
534
+ })
535
+ })
536
+
537
+ describe('getFirstValueIfArray', () => {
538
+ it('should return the first value of arrays', () => {
539
+ const values = {
540
+ phone: [{ phone: '123' }, { phone: '456' }],
541
+ email: [{ email: 'test@example.com' }],
542
+ name: 'John'
543
+ }
544
+
545
+ const res = getFirstValueIfArray(values)
546
+
547
+ expect(res).toEqual({
548
+ phone: { phone: '123' },
549
+ email: { email: 'test@example.com' },
550
+ name: 'John'
551
+ })
552
+ })
553
+
554
+ it('should return undefined for empty arrays', () => {
555
+ const values = {
556
+ phone: [],
557
+ email: [{ email: 'test@example.com' }]
558
+ }
559
+
560
+ const res = getFirstValueIfArray(values)
561
+
562
+ expect(res).toEqual({
563
+ phone: undefined,
564
+ email: { email: 'test@example.com' }
565
+ })
566
+ })
567
+
568
+ it('should not mutate the original object', () => {
569
+ const values = {
570
+ phone: [{ phone: '123' }, { phone: '456' }],
571
+ name: 'John'
572
+ }
573
+ const originalValues = JSON.parse(JSON.stringify(values))
574
+
575
+ getFirstValueIfArray(values)
576
+
577
+ expect(values).toEqual(originalValues)
578
+ })
579
+
580
+ it('should handle non-array values', () => {
581
+ const values = {
582
+ name: 'John',
583
+ age: 30,
584
+ active: true,
585
+ address: null
586
+ }
587
+
588
+ const res = getFirstValueIfArray(values)
589
+
590
+ expect(res).toEqual({
591
+ name: 'John',
592
+ age: 30,
593
+ active: true,
594
+ address: null
595
+ })
596
+ })
597
+
598
+ it('should handle mixed array and non-array values', () => {
599
+ const values = {
600
+ phone: [{ phone: '123' }],
601
+ name: 'John',
602
+ email: []
603
+ }
604
+
605
+ const res = getFirstValueIfArray(values)
606
+
607
+ expect(res).toEqual({
608
+ phone: { phone: '123' },
609
+ name: 'John',
610
+ email: undefined
611
+ })
612
+ })
613
+
614
+ it('should return empty object for empty input', () => {
615
+ const values = {}
616
+
617
+ const res = getFirstValueIfArray(values)
618
+
619
+ expect(res).toEqual({})
620
+ })
621
+ })
622
+
623
+ describe('validateFields', () => {
624
+ it('should return errors for required fields that are empty (non-array fields)', () => {
625
+ const values = {
626
+ name: '',
627
+ email: undefined
628
+ }
629
+ const fields = [
630
+ { name: 'name', required: true },
631
+ { name: 'email', required: true },
632
+ { name: 'phone', required: false }
633
+ ]
634
+
635
+ const res = validateFields(values, fields, t)
636
+
637
+ expect(res).toEqual({
638
+ name: 'All required fields must be filled in',
639
+ email: 'All required fields must be filled in'
640
+ })
641
+ })
642
+
643
+ it('should return errors for required array fields that are empty', () => {
644
+ const values = {
645
+ phone: []
646
+ }
647
+ const fields = [{ name: 'phone', required: true, layout: 'array' }]
648
+
649
+ const res = validateFields(values, fields, t)
650
+
651
+ expect(res).toEqual({
652
+ phone: [
653
+ {
654
+ phone: 'All required fields must be filled in'
655
+ }
656
+ ]
657
+ })
658
+ })
659
+
660
+ it('should not return errors for required array fields with valid first element', () => {
661
+ const values = {
662
+ phone: [{ phone: '123456789' }]
663
+ }
664
+ const fields = [{ name: 'phone', required: true, layout: 'array' }]
665
+
666
+ const res = validateFields(values, fields, t)
667
+
668
+ expect(res).toEqual({})
669
+ })
670
+
671
+ it('should not return errors for non-required fields', () => {
672
+ const values = {
673
+ name: '',
674
+ phone: []
675
+ }
676
+ const fields = [
677
+ { name: 'name', required: false },
678
+ { name: 'phone', required: false, layout: 'array' }
679
+ ]
680
+
681
+ const res = validateFields(values, fields, t)
682
+
683
+ expect(res).toEqual({})
684
+ })
685
+
686
+ it('should handle mixed array and non-array required fields', () => {
687
+ const values = {
688
+ name: '',
689
+ phone: []
690
+ }
691
+ const fields = [
692
+ { name: 'name', required: true },
693
+ { name: 'phone', required: true, layout: 'array' }
694
+ ]
695
+
696
+ const res = validateFields(values, fields, t)
697
+
698
+ expect(res).toEqual({
699
+ name: 'All required fields must be filled in',
700
+ phone: [
701
+ {
702
+ phone: 'All required fields must be filled in'
703
+ }
704
+ ]
705
+ })
706
+ })
707
+
708
+ it('should use getFirstValueIfArray to check only first element of arrays', () => {
709
+ const values = {
710
+ phone: [{ phone: '123' }, {}]
711
+ }
712
+ const fields = [{ name: 'phone', required: true, layout: 'array' }]
713
+
714
+ const res = validateFields(values, fields, t)
715
+
716
+ // Should not return error because first element has phone value
717
+ expect(res).toEqual({})
718
+ })
719
+
720
+ it('should return empty errors object when no required fields are empty', () => {
721
+ const values = {
722
+ name: 'John',
723
+ phone: [{ phone: '123456789' }]
724
+ }
725
+ const fields = [
726
+ { name: 'name', required: true },
727
+ { name: 'phone', required: true, layout: 'array' }
728
+ ]
729
+
730
+ const res = validateFields(values, fields, t)
731
+
732
+ expect(res).toEqual({})
733
+ })
391
734
  })
@@ -1,16 +1,16 @@
1
1
  import arrayMutators from 'final-form-arrays'
2
2
  import React, { useState } from 'react'
3
3
  import { Form } from 'react-final-form'
4
+ import { useI18n, useExtendI18n } from 'twake-i18n'
4
5
 
5
6
  import { getHasManyItems } from 'cozy-client/dist/associations/HasMany'
6
7
  import Button from 'cozy-ui/transpiled/react/Buttons'
7
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
8
8
 
9
9
  import FieldInputLayout from './FieldInputLayout'
10
10
  import contactToFormValues from './contactToFormValues'
11
11
  import { fields as defaultFields } from './fieldsConfig'
12
12
  import formValuesToContact from './formValuesToContact'
13
- import { validateFields, makeFields } from './helpers'
13
+ import { validateFields, makeFields, hasNoValues } from './helpers'
14
14
  import { locales } from './locales'
15
15
  // import { fullContactPropTypes } from '../../ContactPropTypes' // !!
16
16
 
@@ -55,9 +55,14 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
55
55
  makeCustomContactValues,
56
56
  t
57
57
  })}
58
- validate={values => validateFields(values, t)}
59
- onSubmit={formValues =>
60
- onSubmit(
58
+ validate={values => validateFields(values, _fields, t)}
59
+ onSubmit={formValues => {
60
+ // avoid creating an empty contact
61
+ if (hasNoValues(formValues, _fields)) {
62
+ return
63
+ }
64
+
65
+ return onSubmit(
61
66
  formValuesToContact({
62
67
  formValues,
63
68
  oldContact: contact,
@@ -65,7 +70,7 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
65
70
  t
66
71
  })
67
72
  )
68
- }
73
+ }}
69
74
  render={({ handleSubmit, valid, submitFailed, errors }) => {
70
75
  setSubmitContactForm(handleSubmit)
71
76
  return (
@@ -26,7 +26,7 @@
26
26
  "relationship": "Relationship",
27
27
  "note": "Notes",
28
28
  "label": "Label",
29
- "required": "One of these fields must be filled in"
29
+ "required": "All required fields must be filled in"
30
30
  },
31
31
  "label": {
32
32
  "none": "None",
@@ -26,7 +26,7 @@
26
26
  "relationship": "Relation",
27
27
  "note": "Notes",
28
28
  "label": "Libellé",
29
- "required": "Un de ces champs doit être renseigné"
29
+ "required": "Tous les champs requis doivent être renseignés"
30
30
  },
31
31
  "label": {
32
32
  "none": "Aucun",
@@ -26,7 +26,7 @@
26
26
  "relationship": "Отношение",
27
27
  "note": "Заметки",
28
28
  "label": "Метка",
29
- "required": "Одно из этих полей должно быть заполнено"
29
+ "required": "Все обязательные поля должны быть заполнены"
30
30
  },
31
31
  "label": {
32
32
  "none": "Нет",
@@ -26,7 +26,7 @@
26
26
  "relationship": "Mối quan hệ",
27
27
  "note": "Ghi chú",
28
28
  "label": "Nhãn",
29
- "required": "Một trong những trường này phải được điền"
29
+ "required": "Tất cả các trường bắt buộc phải được điền"
30
30
  },
31
31
  "label": {
32
32
  "none": "Không có",
@@ -1,5 +1,6 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import React, { useState } from 'react'
3
+ import { useI18n, useExtendI18n } from 'twake-i18n'
3
4
 
4
5
  import Button from 'cozy-ui/transpiled/react/Buttons'
5
6
  import { ConfirmDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
@@ -8,7 +9,6 @@ import RadioGroup from 'cozy-ui/transpiled/react/RadioGroup'
8
9
  import Radio from 'cozy-ui/transpiled/react/Radios'
9
10
  import TextField from 'cozy-ui/transpiled/react/TextField'
10
11
  import { useBreakpoints } from 'cozy-ui/transpiled/react/providers/Breakpoints'
11
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
12
12
 
13
13
  import { locales } from './locales'
14
14
 
@@ -1,9 +1,9 @@
1
1
  import React, { useState } from 'react'
2
+ import { useI18n, useExtendI18n } from 'twake-i18n'
2
3
 
3
4
  import Button from 'cozy-ui/transpiled/react/Buttons'
4
5
  import { FixedDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
5
6
  import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
6
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
7
7
 
8
8
  import ContactForm, { getSubmitContactForm } from './ContactForm'
9
9
  import { locales } from './locales'
@@ -1,10 +1,10 @@
1
1
  import classNames from 'classnames'
2
2
  import React, { Component } from 'react'
3
+ import { translate } from 'twake-i18n'
3
4
 
4
5
  import Icon from 'cozy-ui/transpiled/react/Icon'
5
6
  import PlusIcon from 'cozy-ui/transpiled/react/Icons/Plus'
6
7
  import Input from 'cozy-ui/transpiled/react/legacy/Input'
7
- import { translate } from 'cozy-ui/transpiled/react/providers/I18n'
8
8
 
9
9
  import styles from './styles.styl'
10
10
 
@@ -1,6 +1,5 @@
1
1
  import React, { useContext, useState } from 'react'
2
-
3
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
2
+ import { useI18n, useExtendI18n } from 'twake-i18n'
4
3
 
5
4
  import { translatedDefaultSelectedGroup } from './helpers'
6
5
  import { locales } from './locales'
@@ -1,10 +1,10 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import React from 'react'
3
+ import { useI18n, useExtendI18n } from 'twake-i18n'
3
4
 
4
5
  import Button from 'cozy-ui/transpiled/react/Buttons'
5
6
  import Icon from 'cozy-ui/transpiled/react/Icon'
6
7
  import BottomSelectIcon from 'cozy-ui/transpiled/react/Icons/BottomSelect'
7
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
8
8
 
9
9
  import { locales } from '../locales'
10
10
 
@@ -1,7 +1,7 @@
1
1
  import get from 'lodash/get'
2
+ import { useI18n, useExtendI18n } from 'twake-i18n'
2
3
 
3
4
  import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
4
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
5
5
 
6
6
  import { useSelectedGroup } from './GroupsSelectProvider'
7
7
  import { isExistingGroup } from './helpers'
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
+ import { useI18n, useExtendI18n } from 'twake-i18n'
2
3
 
3
4
  import { ControlDefault } from 'cozy-ui/transpiled/react/SelectBox'
4
5
  import { useBreakpoints } from 'cozy-ui/transpiled/react/providers/Breakpoints'
5
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
6
6
 
7
7
  import { locales } from './locales'
8
8
  import GroupsSelect from '../GroupsSelect/GroupsSelect'
@@ -1,4 +1,5 @@
1
1
  import React, { useState, useRef } from 'react'
2
+ import { useI18n, useExtendI18n } from 'twake-i18n'
2
3
 
3
4
  import { useClient, generateWebLink } from 'cozy-client'
4
5
  import { CONTACTS_DOCTYPE } from 'cozy-client/dist/models/contact'
@@ -10,7 +11,6 @@ import Link from 'cozy-ui/transpiled/react/Link'
10
11
  import ActionMenu, {
11
12
  ActionMenuItem
12
13
  } from 'cozy-ui/transpiled/react/deprecated/ActionMenu'
13
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
14
14
 
15
15
  import { locales } from './locales'
16
16
  import AppIcon from '../../AppIcon'
@@ -1,12 +1,12 @@
1
1
  import cx from 'classnames'
2
2
  import PropTypes from 'prop-types'
3
3
  import React from 'react'
4
+ import { useI18n, useExtendI18n } from 'twake-i18n'
4
5
 
5
6
  import Button from 'cozy-ui/transpiled/react/Buttons'
6
7
  import Icon from 'cozy-ui/transpiled/react/Icon'
7
8
  import PersonAddIcon from 'cozy-ui/transpiled/react/Icons/PersonAdd'
8
9
  import { useBreakpoints } from 'cozy-ui/transpiled/react/providers/Breakpoints'
9
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
10
10
 
11
11
  import GroupsSelection from './GroupsSelection'
12
12
  import ImportDropdown from './ImportDropdown'
@@ -1,10 +1,10 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import React from 'react'
3
+ import { useI18n, useExtendI18n } from 'twake-i18n'
3
4
 
4
5
  import { getInitials } from 'cozy-client/dist/models/contact'
5
6
  import Avatar from 'cozy-ui/transpiled/react/Avatar'
6
7
  import { TableCell } from 'cozy-ui/transpiled/react/deprecated/Table'
7
- import { useI18n, useExtendI18n } from 'cozy-ui/transpiled/react/providers/I18n'
8
8
 
9
9
  import ContactName from './ContactName'
10
10
  import { locales } from '../locales/withContactsListLocales'
@@ -1,11 +1,11 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import React from 'react'
3
+ import { useI18n } from 'twake-i18n'
3
4
 
4
5
  import List from 'cozy-ui/transpiled/react/List'
5
6
  import ListSubheader from 'cozy-ui/transpiled/react/ListSubheader'
6
7
  import { Table } from 'cozy-ui/transpiled/react/deprecated/Table'
7
8
  import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'
8
- import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
9
9
 
10
10
  import ContactRow from './ContactRow'
11
11
  import { sortContacts, categorizeContacts, sortHeaders } from './helpers'