cozy-ui-plus 4.0.0 → 4.2.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 (26) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/Contacts/AddModal/ContactForm/FieldInput.js +3 -7
  3. package/dist/Contacts/AddModal/ContactForm/FieldInputArray.js +3 -5
  4. package/dist/Contacts/AddModal/ContactForm/FieldInputLayout.js +2 -4
  5. package/dist/Contacts/AddModal/ContactForm/FieldInputWrapper.js +1 -1
  6. package/dist/Contacts/AddModal/ContactForm/contactToFormValues.js +75 -90
  7. package/dist/Contacts/AddModal/ContactForm/helpers.js +104 -34
  8. package/dist/Contacts/AddModal/ContactForm/index.js +7 -2
  9. package/dist/Contacts/AddModal/ContactForm/locales/index.js +4 -4
  10. package/dist/src/Contacts/AddModal/ContactForm/FieldInput.d.ts +2 -6
  11. package/dist/src/Contacts/AddModal/ContactForm/FieldInputArray.d.ts +2 -6
  12. package/dist/src/Contacts/AddModal/ContactForm/helpers.d.ts +5 -2
  13. package/package.json +2 -2
  14. package/src/Contacts/AddModal/ContactForm/FieldInput.jsx +3 -7
  15. package/src/Contacts/AddModal/ContactForm/FieldInputArray.jsx +7 -4
  16. package/src/Contacts/AddModal/ContactForm/FieldInputLayout.jsx +3 -3
  17. package/src/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx +1 -1
  18. package/src/Contacts/AddModal/ContactForm/contactToFormValues.js +79 -94
  19. package/src/Contacts/AddModal/ContactForm/contactToFormValues.spec.js +0 -23
  20. package/src/Contacts/AddModal/ContactForm/helpers.js +77 -17
  21. package/src/Contacts/AddModal/ContactForm/helpers.spec.js +344 -1
  22. package/src/Contacts/AddModal/ContactForm/index.jsx +24 -10
  23. package/src/Contacts/AddModal/ContactForm/locales/en.json +1 -1
  24. package/src/Contacts/AddModal/ContactForm/locales/fr.json +1 -1
  25. package/src/Contacts/AddModal/ContactForm/locales/ru.json +1 -1
  26. package/src/Contacts/AddModal/ContactForm/locales/vi.json +1 -1
@@ -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
  })
@@ -10,7 +10,12 @@ 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 {
14
+ validateFields,
15
+ makeFields,
16
+ hasNoValues,
17
+ initializationFieldValues
18
+ } from './helpers'
14
19
  import { locales } from './locales'
15
20
  // import { fullContactPropTypes } from '../../ContactPropTypes' // !!
16
21
 
@@ -50,14 +55,23 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
50
55
  return (
51
56
  <Form
52
57
  mutators={{ ...arrayMutators }}
53
- initialValues={contactToFormValues({
54
- contact,
55
- makeCustomContactValues,
56
- t
57
- })}
58
- validate={values => validateFields(values, t)}
59
- onSubmit={formValues =>
60
- onSubmit(
58
+ initialValues={
59
+ !contact
60
+ ? initializationFieldValues(_fields)
61
+ : contactToFormValues({
62
+ contact,
63
+ makeCustomContactValues,
64
+ t
65
+ })
66
+ }
67
+ validate={values => validateFields(values, _fields, t)}
68
+ onSubmit={formValues => {
69
+ // avoid creating an empty contact
70
+ if (hasNoValues(formValues, _fields)) {
71
+ return
72
+ }
73
+
74
+ return onSubmit(
61
75
  formValuesToContact({
62
76
  formValues,
63
77
  oldContact: contact,
@@ -65,7 +79,7 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
65
79
  t
66
80
  })
67
81
  )
68
- }
82
+ }}
69
83
  render={({ handleSubmit, valid, submitFailed, errors }) => {
70
84
  setSubmitContactForm(handleSubmit)
71
85
  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ó",