@coorpacademy/app-review 0.1.9 → 0.1.11

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 (70) hide show
  1. package/es/actions/ui/navigation.d.ts +1 -1
  2. package/es/fixtures/qcm-slide.js +1 -1
  3. package/es/helpers/map-api-slide-to-ui.d.ts +8 -0
  4. package/es/helpers/map-api-slide-to-ui.js +175 -0
  5. package/es/helpers/test/fixtures/free-text.d.ts +4 -0
  6. package/es/helpers/test/fixtures/free-text.js +24 -0
  7. package/es/helpers/test/fixtures/qcm-drag.d.ts +4 -0
  8. package/es/helpers/test/fixtures/qcm-drag.js +106 -0
  9. package/es/helpers/test/fixtures/qcm-graphic.d.ts +4 -0
  10. package/es/helpers/test/fixtures/qcm-graphic.js +70 -0
  11. package/es/helpers/test/fixtures/qcm.d.ts +4 -0
  12. package/es/helpers/test/fixtures/qcm.js +99 -0
  13. package/es/helpers/test/fixtures/select-template.d.ts +4 -0
  14. package/es/helpers/test/fixtures/select-template.js +88 -0
  15. package/es/helpers/test/fixtures/slider.d.ts +4 -0
  16. package/es/helpers/test/fixtures/slider.js +27 -0
  17. package/es/helpers/test/fixtures/text-template.d.ts +4 -0
  18. package/es/helpers/test/fixtures/text-template.js +48 -0
  19. package/es/helpers/test/map-api-slide-to-ui.test.d.ts +1 -0
  20. package/es/helpers/test/map-api-slide-to-ui.test.js +32 -0
  21. package/es/index.js +29 -9
  22. package/es/reducers/ui/navigation.d.ts +1 -1
  23. package/es/test/index.test.js +18 -15
  24. package/es/test/util/services.mock.js +2 -32
  25. package/es/types/common.d.ts +62 -5
  26. package/es/types/slides.d.ts +27 -16
  27. package/lib/actions/ui/navigation.d.ts +1 -1
  28. package/lib/fixtures/qcm-slide.js +1 -1
  29. package/lib/helpers/map-api-slide-to-ui.d.ts +8 -0
  30. package/lib/helpers/map-api-slide-to-ui.js +181 -0
  31. package/lib/helpers/test/fixtures/free-text.d.ts +4 -0
  32. package/lib/helpers/test/fixtures/free-text.js +24 -0
  33. package/lib/helpers/test/fixtures/qcm-drag.d.ts +4 -0
  34. package/lib/helpers/test/fixtures/qcm-drag.js +106 -0
  35. package/lib/helpers/test/fixtures/qcm-graphic.d.ts +4 -0
  36. package/lib/helpers/test/fixtures/qcm-graphic.js +70 -0
  37. package/lib/helpers/test/fixtures/qcm.d.ts +4 -0
  38. package/lib/helpers/test/fixtures/qcm.js +99 -0
  39. package/lib/helpers/test/fixtures/select-template.d.ts +4 -0
  40. package/lib/helpers/test/fixtures/select-template.js +88 -0
  41. package/lib/helpers/test/fixtures/slider.d.ts +4 -0
  42. package/lib/helpers/test/fixtures/slider.js +27 -0
  43. package/lib/helpers/test/fixtures/text-template.d.ts +4 -0
  44. package/lib/helpers/test/fixtures/text-template.js +48 -0
  45. package/lib/helpers/test/map-api-slide-to-ui.test.d.ts +1 -0
  46. package/lib/helpers/test/map-api-slide-to-ui.test.js +43 -0
  47. package/lib/index.js +29 -9
  48. package/lib/reducers/ui/navigation.d.ts +1 -1
  49. package/lib/test/index.test.js +19 -16
  50. package/lib/test/util/services.mock.js +13 -32
  51. package/lib/types/common.d.ts +62 -5
  52. package/lib/types/slides.d.ts +27 -16
  53. package/package.json +4 -3
  54. package/src/actions/ui/navigation.ts +1 -1
  55. package/src/fixtures/qcm-slide.ts +1 -1
  56. package/src/helpers/map-api-slide-to-ui.ts +253 -0
  57. package/src/helpers/test/fixtures/free-text.ts +28 -0
  58. package/src/helpers/test/fixtures/qcm-drag.ts +110 -0
  59. package/src/helpers/test/fixtures/qcm-graphic.ts +74 -0
  60. package/src/helpers/test/fixtures/qcm.ts +108 -0
  61. package/src/helpers/test/fixtures/select-template.ts +92 -0
  62. package/src/helpers/test/fixtures/slider.ts +31 -0
  63. package/src/helpers/test/fixtures/text-template.ts +52 -0
  64. package/src/helpers/test/map-api-slide-to-ui.test.ts +55 -0
  65. package/src/index.tsx +35 -11
  66. package/src/reducers/ui/navigation.ts +1 -1
  67. package/src/test/index.test.tsx +23 -12
  68. package/src/test/util/services.mock.ts +2 -32
  69. package/src/types/common.ts +74 -5
  70. package/src/types/slides.ts +29 -12
@@ -0,0 +1,74 @@
1
+ import noop from 'lodash/fp/noop';
2
+ import {QcmGraphic} from '../../../types/slides';
3
+ import {SlideFromAPI} from '../../../types/common';
4
+
5
+ export const qcmGraphicSlide: SlideFromAPI = {
6
+ id: 'sli_41~RSVclH',
7
+ universalRef: 'sli_41~RSVclH',
8
+ question: {
9
+ type: 'qcmGraphic',
10
+ header: 'sli_41~RSVclH.header',
11
+ explanation: 'sli_41~RSVclH.explanation',
12
+ content: {
13
+ choices: [
14
+ {
15
+ media: {
16
+ type: 'img',
17
+ src: [
18
+ {
19
+ _id: '5fdce726359bf4003ee66997',
20
+ mimeType: 'image/png',
21
+ url: 'med_4JVRrE5gH.mediaUrl_VkBtUV9gB'
22
+ }
23
+ ],
24
+ posters: [],
25
+ subtitles: []
26
+ },
27
+ _id: '5fdce726359bf4003ee66996',
28
+ label: 'sli_41~RSVclH.choice_V1gN0r4qgS',
29
+ value: 'sli_41~RSVclH.choice_V1gN0r4qgS',
30
+ items: []
31
+ },
32
+ {
33
+ media: {
34
+ type: 'img',
35
+ src: [
36
+ {
37
+ _id: '5fdce726359bf4003ee66999',
38
+ mimeType: 'image/png',
39
+ url: 'med_Ek8gIEqxB.mediaUrl_EkcFUEclH'
40
+ }
41
+ ],
42
+ posters: [],
43
+ subtitles: []
44
+ },
45
+ _id: '5fdce726359bf4003ee66998',
46
+ label: 'sli_41~RSVclH.choice_4JlLeLE5lS',
47
+ value: 'sli_41~RSVclH.choice_4JlLeLE5lS',
48
+ items: []
49
+ }
50
+ ]
51
+ }
52
+ },
53
+ clue: 'sli_41~RSVclH.clue',
54
+ klf: 'sli_41~RSVclH.klf',
55
+ tips: 'sli_41~RSVclH.tips'
56
+ };
57
+
58
+ export const qcmGraphicUISlide: QcmGraphic = {
59
+ type: 'qcmGraphic',
60
+ answers: [
61
+ {
62
+ title: 'sli_41~RSVclH.choice_V1gN0r4qgS',
63
+ image: 'med_4JVRrE5gH.mediaUrl_VkBtUV9gB',
64
+ selected: false,
65
+ onClick: noop
66
+ },
67
+ {
68
+ title: 'sli_41~RSVclH.choice_4JlLeLE5lS',
69
+ image: 'med_Ek8gIEqxB.mediaUrl_EkcFUEclH',
70
+ selected: false,
71
+ onClick: noop
72
+ }
73
+ ]
74
+ };
@@ -0,0 +1,108 @@
1
+ import noop from 'lodash/fp/noop';
2
+ import {Qcm} from '../../../types/slides';
3
+ import {SlideFromAPI} from '../../../types/common';
4
+
5
+ export const qcmSlide: SlideFromAPI = {
6
+ question: {
7
+ content: {
8
+ media: {
9
+ src: [],
10
+ posters: [],
11
+ subtitles: []
12
+ },
13
+ choices: [
14
+ {
15
+ media: {
16
+ src: [],
17
+ posters: [],
18
+ subtitles: []
19
+ },
20
+ items: [],
21
+ _id: '62c853412d0f9b088718e759',
22
+ label: 'Le créateur peut fixer un pourcentage pour chaque transaction future',
23
+ value: 'sli_N1XACJobn.choice_4JjaSesZh',
24
+ id: '62c853412d0f9b088718e759'
25
+ },
26
+ {
27
+ media: {
28
+ src: [],
29
+ posters: [],
30
+ subtitles: []
31
+ },
32
+ items: [],
33
+ _id: '62c853412d0f9b088718e75a',
34
+ label:
35
+ "Pour chaque transaction il existe un pourcentage fixe déterminé par le droit d'auteur du pays où se tient la vente",
36
+ value: 'sli_N1XACJobn.choice_Ny78UlsWh',
37
+ id: '62c853412d0f9b088718e75a'
38
+ },
39
+ {
40
+ media: {
41
+ src: [],
42
+ posters: [],
43
+ subtitles: []
44
+ },
45
+ items: [],
46
+ _id: '62c853412d0f9b088718e75b',
47
+ label:
48
+ "Seule la galerie ou la plateforme peut toucher une commission sur la vente d'un NFT",
49
+ value: 'sli_N1XACJobn.choice_Eypt8esW2',
50
+ id: '62c853412d0f9b088718e75b'
51
+ },
52
+ {
53
+ media: {
54
+ src: [],
55
+ posters: [],
56
+ subtitles: []
57
+ },
58
+ items: [],
59
+ _id: '62c853412d0f9b088718e75c',
60
+ label: "Les NFT payés en ETH ne peuvent pas être soumis au paiement d'une commission",
61
+ value: 'sli_N1XACJobn.choice_VyS3LxjZh',
62
+ id: '62c853412d0f9b088718e75c'
63
+ }
64
+ ]
65
+ },
66
+ type: 'qcm',
67
+ header: "Après la vente d'un NFT, son créateur peut-il toucher de l'argent ?",
68
+ explanation: 'Sélectionnez la bonne réponse.'
69
+ },
70
+ klf: 'Si vous êtes le créateur d’un NFT, vous pouvez choisir le pourcentage de commission pour chaque transaction de votre NFT. Certains choisissent de ne rien toucher pour fluidifier le marché.',
71
+ tips: 'En 2021, le média en ligne Numerama a créé un NFT vendu aux enchères sur OpenSea. Sur cette plateforme, il est obligatoire de mettre un prix de réserve, autrement dit un prix minimum au-dessous duquel la vente ne sera pas automatiquement acceptée. Sur OpenSea il ne peut être inférieur à 1 ETH. Si le prix de réserve est atteint, pas de problème, les "gas fees" (les frais de gaz) sont couverts par OpenSea. Mais, si ce n’est pas le cas, c’est au vendeur de s’en acquitter. <br/>Le NFT en question est parti à 0,021 ETH, soit 40€ au cours de l\'époque, un prix inférieur au prix de réserve. Numerama a dû acquitter des frais de gaz, et payer 190 €. <br/>Avec les NFT, on ne gagne pas à tous les coups.',
72
+ universalRef: 'sli_N1XACJobn',
73
+ hasClue: true,
74
+ id: 'sli_N1XACJobn'
75
+ };
76
+
77
+ export const qcmUISlide: Qcm = {
78
+ type: 'qcm',
79
+ answers: [
80
+ {
81
+ title: 'Le créateur peut fixer un pourcentage pour chaque transaction future',
82
+ selected: false,
83
+ onClick: noop,
84
+ ariaLabel: 'Le créateur peut fixer un pourcentage pour chaque transaction future'
85
+ },
86
+ {
87
+ title:
88
+ "Pour chaque transaction il existe un pourcentage fixe déterminé par le droit d'auteur du pays où se tient la vente",
89
+ selected: false,
90
+ onClick: noop,
91
+ ariaLabel:
92
+ "Pour chaque transaction il existe un pourcentage fixe déterminé par le droit d'auteur du pays où se tient la vente"
93
+ },
94
+ {
95
+ title: "Seule la galerie ou la plateforme peut toucher une commission sur la vente d'un NFT",
96
+ selected: false,
97
+ onClick: noop,
98
+ ariaLabel:
99
+ "Seule la galerie ou la plateforme peut toucher une commission sur la vente d'un NFT"
100
+ },
101
+ {
102
+ title: "Les NFT payés en ETH ne peuvent pas être soumis au paiement d'une commission",
103
+ selected: false,
104
+ onClick: noop,
105
+ ariaLabel: "Les NFT payés en ETH ne peuvent pas être soumis au paiement d'une commission"
106
+ }
107
+ ]
108
+ };
@@ -0,0 +1,92 @@
1
+ import noop from 'lodash/fp/noop';
2
+ import {Template} from '../../../types/slides';
3
+ import {SlideFromAPI} from '../../../types/common';
4
+
5
+ export const selectTemplateSlide: SlideFromAPI = {
6
+ id: 'sli_410xZQxrZ',
7
+ universalRef: 'sli_410xZQxrZ',
8
+ question: {
9
+ type: 'template',
10
+ header: 'sli_410xZQxrZ.header',
11
+ explanation: 'sli_410xZQxrZ.explanation',
12
+ content: {
13
+ template: 'sli_410xZQxrZ.template',
14
+ choices: [
15
+ {
16
+ media: {
17
+ src: [],
18
+ posters: [],
19
+ subtitles: []
20
+ },
21
+ _id: '5fdce726359bf4003ee66967',
22
+ type: 'select',
23
+ name: 'sel36665',
24
+ items: [
25
+ {
26
+ _id: '5fdce726359bf4003ee66968',
27
+ text: 'sli_410xZQxrZ.choice_4yeA4Z7lr~',
28
+ value: 'sli_410xZQxrZ.choice_4yeA4Z7lr~'
29
+ },
30
+ {
31
+ _id: '5fdce726359bf4003ee66969',
32
+ text: 'sli_410xZQxrZ.choice_VJWCN~mgB~',
33
+ value: 'sli_410xZQxrZ.choice_VJWCN~mgB~'
34
+ },
35
+ {
36
+ _id: '5fdce726359bf4003ee6696a',
37
+ text: 'sli_410xZQxrZ.choice_VkaH~XgBb',
38
+ value: 'sli_410xZQxrZ.choice_VkaH~XgBb'
39
+ },
40
+ {
41
+ _id: '5fdce726359bf4003ee6696b',
42
+ text: 'sli_410xZQxrZ.choice_E1uUWXeBb',
43
+ value: 'sli_410xZQxrZ.choice_E1uUWXeBb'
44
+ }
45
+ ]
46
+ }
47
+ ]
48
+ }
49
+ },
50
+ clue: 'sli_410xZQxrZ.clue',
51
+ klf: 'sli_410xZQxrZ.klf',
52
+ tips: 'sli_410xZQxrZ.tips'
53
+ };
54
+
55
+ export const selectTemplateUISlide: Template = {
56
+ type: 'template',
57
+ template: 'sli_410xZQxrZ.template',
58
+ answers: [
59
+ {
60
+ type: 'select',
61
+ name: 'sel36665',
62
+ onChange: noop,
63
+ options: [
64
+ {name: 'Select an answer', value: '', validOption: false, selected: true},
65
+ {
66
+ name: 'sli_410xZQxrZ.choice_4yeA4Z7lr~',
67
+ value: 'sli_410xZQxrZ.choice_4yeA4Z7lr~',
68
+ validOption: true,
69
+ selected: false
70
+ },
71
+ {
72
+ name: 'sli_410xZQxrZ.choice_VJWCN~mgB~',
73
+ value: 'sli_410xZQxrZ.choice_VJWCN~mgB~',
74
+ validOption: true,
75
+ selected: false
76
+ },
77
+ {
78
+ name: 'sli_410xZQxrZ.choice_VkaH~XgBb',
79
+ value: 'sli_410xZQxrZ.choice_VkaH~XgBb',
80
+ validOption: true,
81
+ selected: false
82
+ },
83
+ {
84
+ name: 'sli_410xZQxrZ.choice_E1uUWXeBb',
85
+ value: 'sli_410xZQxrZ.choice_E1uUWXeBb',
86
+ validOption: true,
87
+ selected: false
88
+ }
89
+ ]
90
+ }
91
+ ]
92
+ };
@@ -0,0 +1,31 @@
1
+ import noop from 'lodash/fp/noop';
2
+ import {QuestionRange} from '../../../types/slides';
3
+ import {SlideFromAPI} from '../../../types/common';
4
+
5
+ export const sliderSlide: SlideFromAPI = {
6
+ id: 'sli_41D5AovN~',
7
+ universalRef: 'sli_41D5AovN~',
8
+ question: {
9
+ type: 'slider',
10
+ header: 'sli_41D5AovN~.header',
11
+ explanation: 'sli_41D5AovN~.explanation',
12
+ content: {
13
+ min: 1,
14
+ max: 10,
15
+ unitLabel: 'sli_41D5AovN~.unitLabel'
16
+ }
17
+ },
18
+ clue: 'sli_41D5AovN~.clue',
19
+ klf: 'sli_41D5AovN~.klf',
20
+ tips: 'sli_41D5AovN~.tips'
21
+ };
22
+
23
+ export const sliderUISlide: QuestionRange = {
24
+ type: 'slider',
25
+ placeholder: 'sli_41D5AovN~.explanation',
26
+ minLabel: '1 undefined',
27
+ maxLabel: '10 undefined',
28
+ title: '0 sli_41D5AovN~.unitLabel',
29
+ value: -0.1111111111111111,
30
+ onChange: noop
31
+ };
@@ -0,0 +1,52 @@
1
+ import noop from 'lodash/fp/noop';
2
+ import {Template} from '../../../types/slides';
3
+ import {SlideFromAPI} from '../../../types/common';
4
+
5
+ export const textTemplateSlide: SlideFromAPI = {
6
+ question: {
7
+ content: {
8
+ media: {
9
+ src: [],
10
+ posters: [],
11
+ subtitles: []
12
+ },
13
+ template: 'Un {{inp58402}} model.',
14
+ choices: [
15
+ {
16
+ media: {
17
+ src: [],
18
+ posters: [],
19
+ subtitles: []
20
+ },
21
+ items: [],
22
+ _id: '62433c2c58920f02c4950de0',
23
+ type: 'text',
24
+ name: 'inp58402',
25
+ id: '62433c2c58920f02c4950de0'
26
+ }
27
+ ]
28
+ },
29
+ type: 'template',
30
+ header: 'Comment le protégé doit-il percevoir son mentor ?',
31
+ explanation: 'Saisissez votre réponse (en anglais).'
32
+ },
33
+ klf: "Le mentoré voit dans son mentor un <i>role model</i>, c'est-à-dire un exemple inspirant qui lui permet de se projeter dans un poste à responsabilité.",
34
+ tips: "L'origine de l'expression <i>role model</i> est attribué au sociologue Robert K. Merton.",
35
+ universalRef: 'sli_VJKQonm2g',
36
+ hasClue: true,
37
+ id: 'sli_VJKQonm2g'
38
+ };
39
+
40
+ export const textTemplateUISlide: Template = {
41
+ type: 'template',
42
+ template: 'Un {{inp58402}} model.',
43
+ answers: [
44
+ {
45
+ type: 'text',
46
+ name: 'inp58402',
47
+ placeholder: 'Type here',
48
+ value: undefined,
49
+ onChange: noop
50
+ }
51
+ ]
52
+ };
@@ -0,0 +1,55 @@
1
+ import test from 'ava';
2
+ import {SlideFromAPI} from '../../types/common';
3
+ import {mapApiSlideToUi} from '../map-api-slide-to-ui';
4
+ import {
5
+ QcmDrag,
6
+ Qcm,
7
+ QcmGraphic,
8
+ FreeText,
9
+ DropDown,
10
+ QuestionRange,
11
+ Template
12
+ } from '../../types/slides';
13
+ import {qcmUISlide, qcmSlide} from './fixtures/qcm';
14
+ import {qcmDragUISlide, qcmDragSlide} from './fixtures/qcm-drag';
15
+ import {freeTextSlide, freeTextUISlide} from './fixtures/free-text';
16
+ import {qcmGraphicUISlide, qcmGraphicSlide} from './fixtures/qcm-graphic';
17
+ import {textTemplateSlide, textTemplateUISlide} from './fixtures/text-template';
18
+ import {selectTemplateSlide, selectTemplateUISlide} from './fixtures/select-template';
19
+ import {sliderSlide, sliderUISlide} from './fixtures/slider';
20
+
21
+ const _mapApiSlideToUi = mapApiSlideToUi({translate: (text: string) => text});
22
+
23
+ const macro = test.macro({
24
+ title(providedTitle) {
25
+ return `should handle ${providedTitle} conversion`.trim();
26
+ },
27
+ exec(
28
+ t,
29
+ arg: {
30
+ slide: SlideFromAPI;
31
+ expectedUiSlide: QcmDrag | Qcm | QcmGraphic | FreeText | DropDown | QuestionRange | Template;
32
+ }
33
+ ) {
34
+ t.deepEqual(
35
+ JSON.parse(JSON.stringify(_mapApiSlideToUi(arg.slide))),
36
+ JSON.parse(JSON.stringify(arg.expectedUiSlide))
37
+ );
38
+ }
39
+ });
40
+
41
+ test('qcm', macro, {slide: qcmSlide, expectedUiSlide: qcmUISlide});
42
+ test('qcm drag', macro, {slide: qcmDragSlide, expectedUiSlide: qcmDragUISlide});
43
+ test('qcm graphic', macro, {slide: qcmGraphicSlide, expectedUiSlide: qcmGraphicUISlide});
44
+ test('text template', macro, {slide: textTemplateSlide, expectedUiSlide: textTemplateUISlide});
45
+ test('select template', macro, {
46
+ slide: selectTemplateSlide,
47
+ expectedUiSlide: selectTemplateUISlide
48
+ });
49
+ test('free text', macro, {slide: freeTextSlide, expectedUiSlide: freeTextUISlide});
50
+ test('slider', macro, {slide: sliderSlide, expectedUiSlide: sliderUISlide});
51
+
52
+ test('should throw an error if the question type can not be handled', t => {
53
+ const faultySlide = {...qcmSlide, question: {type: 'lol'}};
54
+ t.throws(() => _mapApiSlideToUi(faultySlide as SlideFromAPI));
55
+ });
package/src/index.tsx CHANGED
@@ -5,6 +5,8 @@ import {connect, Provider} from 'react-redux';
5
5
  import AppReviewTemplate from '@coorpacademy/components/es/template/app-review';
6
6
  import {TemplateContext} from '@coorpacademy/components/es/template/app-review/template-context';
7
7
 
8
+ import isEmpty from 'lodash/fp/isEmpty';
9
+ import get from 'lodash/fp/get';
8
10
  import configureStore from './configure-store';
9
11
  import {congratsProps, correctionPopinProps} from './fixtures/temp-fixture';
10
12
 
@@ -25,7 +27,7 @@ import {postProgression} from './actions/api/post-progression';
25
27
  import {VIEWS} from './common';
26
28
 
27
29
  type StaticProps = {
28
- viewName: 'skills' | 'onboarding' | 'slides';
30
+ viewName: 'skills' | 'onboarding' | 'slides' | 'loader';
29
31
  slides: SlidesViewStaticProps | null;
30
32
  skills: SkillsProps | null;
31
33
  };
@@ -113,6 +115,7 @@ const App = connect(mapStateToProps, mapDispatchToProps)(AppReviewTemplate);
113
115
 
114
116
  const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
115
117
  const [store, setStore] = useState<Store<StoreState, AnyAction> | null>(null);
118
+ const [isSlideFetched, setIsSlideFetched] = useState(false);
116
119
 
117
120
  useEffect(() => {
118
121
  if (store) return;
@@ -122,24 +125,27 @@ const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
122
125
  }, [options, store]);
123
126
 
124
127
  useEffect(() => {
125
- if (store === null) return;
128
+ if (!store || isSlideFetched) return;
126
129
 
127
- const {skillRef} = options;
128
- const initialView: ViewPath = skillRef ? VIEWS.slides : VIEWS.skills;
129
- store.dispatch(navigateTo(initialView));
130
- }, [options, store]);
130
+ return store.subscribe(() => {
131
+ const isSlidePresent = !isEmpty(store.getState().data.slides[0].questionText);
132
+ return isSlidePresent && setIsSlideFetched(isSlidePresent);
133
+ }); // using the first slide questionText for now, should only check for a slide's presence
134
+ // when the refactor is done (slides will be feed one by one on api's side)
135
+ }, [isSlideFetched, options, store]);
131
136
 
132
137
  useEffect(() => {
133
- if (store === null) return;
134
-
135
- const {token} = options;
138
+ const token = get('token', options);
139
+ if (store === null || isEmpty(token)) return;
136
140
  store.dispatch(storeToken(token));
137
141
  }, [options, store]);
138
142
 
139
143
  useEffect(() => {
140
- if (store === null) return;
144
+ const token = get('token', options);
145
+ if (store === null || isEmpty(token)) return;
146
+
147
+ const skillRef = get('skillRef', options);
141
148
 
142
- const {skillRef, token} = options;
143
149
  // ThunkAction is not assignable to parameter of type 'AnyAction'
144
150
  // ts problem describre here = https://github.com/reduxjs/redux-thunk/issues/333
145
151
  skillRef
@@ -147,6 +153,24 @@ const AppReview = ({options}: {options: AppOptions}): JSX.Element | null => {
147
153
  : store.dispatch(fetchSkills(token));
148
154
  }, [options, store]);
149
155
 
156
+ useEffect(() => {
157
+ if (store === null) return;
158
+
159
+ const {skillRef} = options;
160
+
161
+ if (skillRef && !isSlideFetched) {
162
+ store.dispatch(navigateTo('loader')); // use loader while posting progression
163
+ return;
164
+ }
165
+
166
+ // TODO: when slides state is refactored (data + mapping),
167
+ // use loader in case a skillRef is found && no slides from the API
168
+ // are found
169
+
170
+ const initialView: ViewPath = skillRef ? VIEWS.slides : VIEWS.skills;
171
+ store.dispatch(navigateTo(initialView));
172
+ }, [isSlideFetched, options, store]);
173
+
150
174
  if (!store) return null;
151
175
 
152
176
  const {templateContext: values} = options;
@@ -5,7 +5,7 @@ import {
5
5
  NAVIGATE_TO
6
6
  } from '../../actions/ui/navigation';
7
7
 
8
- export type NavigationState = Array<'skills' | 'onboarding' | 'slides'>;
8
+ export type NavigationState = Array<'skills' | 'onboarding' | 'slides' | 'loader'>;
9
9
 
10
10
  const reducer = (
11
11
  // eslint-disable-next-line default-param-last
@@ -65,24 +65,35 @@ const appOptions: AppOptions = {
65
65
  services
66
66
  };
67
67
 
68
- test('should validate all the slides (all correct scenario)', async t => {
69
- // t.plan(13);
68
+ test('should show the loader while the app is fetching the data', async t => {
70
69
  t.plan(2);
71
- const {container} = render(<AppReview options={appOptions} key={0} />);
70
+ const {container} = render(<AppReview options={appOptions} />);
71
+
72
72
  await waitForChanges(1000);
73
73
 
74
- const wrapper = container.querySelector('[data-name="loader"]');
75
- t.truthy(wrapper);
76
- /*
77
- const wrapper = container.querySelector('[data-name="slides-revision-container"]');
78
- t.truthy(wrapper);
74
+ const loader = container.querySelector('[data-name="loader"]');
75
+ t.truthy(loader);
76
+
77
+ // await waitFor(async () => {
78
+ // // await sleep(500);
79
+ // const result = await t.try(tt => {
80
+ // // rerender(<AppReview options={appOptions} />);
81
+
82
+ // const slidesContainer = container.querySelector('[data-name="slides-revision-container"]');
83
+
84
+ // tt.truthy(slidesContainer);
85
+ // });
86
+
87
+ // if (result.passed) return result.commit();
88
+ // result.discard();
89
+ // throw result.errors;
90
+ // });
79
91
 
80
- const stackedSlidesContainer = wrapper?.querySelector('[data-name="stacked-slides-container"]');
92
+ // const stackedSlidesContainer = container.querySelector('[data-name="stacked-slides-container"]');
81
93
 
82
- t.truthy(stackedSlidesContainer);
94
+ // t.truthy(stackedSlidesContainer);
83
95
 
84
- await clickAllSlides(t, container);
85
- */
96
+ // await clickAllSlides(t, container);
86
97
 
87
98
  t.pass();
88
99
  });
@@ -1,3 +1,4 @@
1
+ import {qcmSlide} from '../../helpers/test/fixtures/qcm';
1
2
  import {Services} from '../../types/common';
2
3
 
3
4
  export const services: Services = {
@@ -18,38 +19,7 @@ export const services: Services = {
18
19
  ]);
19
20
  },
20
21
  fetchSlide: ref => {
21
- // return Promise.resolve(qcm); // why qcm does not look like a slide returned from mooc ?
22
- return Promise.resolve({
23
- question: {
24
- content: {
25
- choices: [
26
- {
27
- selected: false,
28
- title: 'choix1',
29
- help: '(help choix1)',
30
- ariaLabel: '__ariaLabel1',
31
- onClick: (): void => undefined
32
- },
33
- {
34
- selected: false,
35
- title: 'choix2',
36
- help: '(help choix2)',
37
- ariaLabel: '__ariaLabel2',
38
- onClick: (): void => undefined
39
- },
40
- {
41
- selected: false,
42
- title: 'choix3',
43
- help: '(help choix3)',
44
- ariaLabel: '__ariaLabel3',
45
- onClick: (): void => undefined
46
- }
47
- ]
48
- }
49
- },
50
- klf: '___klf',
51
- universalRef: ref
52
- });
22
+ return Promise.resolve({...qcmSlide, universalRef: ref, id: ref});
53
23
  },
54
24
  postProgression: () => {
55
25
  return Promise.resolve({