@coorpacademy/app-review 0.7.7-alpha.3 → 0.7.7-alpha.61

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 (58) hide show
  1. package/es/actions/api/fetch-skill.d.ts +11 -0
  2. package/es/actions/api/fetch-skill.js +16 -0
  3. package/es/actions/api/post-progression.js +2 -0
  4. package/es/index.js +1 -1
  5. package/es/reducers/data/current-skill.d.ts +5 -0
  6. package/es/reducers/data/current-skill.js +13 -0
  7. package/es/reducers/data/index.d.ts +4 -1
  8. package/es/reducers/data/index.js +10 -1
  9. package/es/reducers/index.d.ts +2 -1
  10. package/es/services/fetch-skill.js +2 -1
  11. package/es/types/common.d.ts +5 -2
  12. package/es/views/skills/index.d.ts +3 -23
  13. package/es/views/skills/index.js +17 -11
  14. package/es/views/slides/index.js +25 -13
  15. package/es/views/slides/map-api-slide-to-ui.d.ts +2 -2
  16. package/es/views/slides/map-api-slide-to-ui.js +14 -11
  17. package/lib/actions/api/fetch-skill.d.ts +11 -0
  18. package/lib/actions/api/fetch-skill.js +23 -0
  19. package/lib/actions/api/post-progression.js +2 -0
  20. package/lib/index.js +1 -1
  21. package/lib/reducers/data/current-skill.d.ts +5 -0
  22. package/lib/reducers/data/current-skill.js +15 -0
  23. package/lib/reducers/data/index.d.ts +4 -1
  24. package/lib/reducers/data/index.js +10 -1
  25. package/lib/reducers/index.d.ts +2 -1
  26. package/lib/services/fetch-skill.js +2 -1
  27. package/lib/types/common.d.ts +5 -2
  28. package/lib/views/skills/index.d.ts +3 -23
  29. package/lib/views/skills/index.js +17 -11
  30. package/lib/views/slides/index.js +25 -13
  31. package/lib/views/slides/map-api-slide-to-ui.d.ts +2 -2
  32. package/lib/views/slides/map-api-slide-to-ui.js +14 -11
  33. package/locales/.mtslconfig.json +1 -0
  34. package/locales/cs/review.json +4 -1
  35. package/locales/de/review.json +4 -1
  36. package/locales/en/review.json +11 -12
  37. package/locales/es/review.json +4 -1
  38. package/locales/fr/review.json +4 -1
  39. package/locales/hr/review.json +4 -1
  40. package/locales/hu/review.json +4 -1
  41. package/locales/id/review.json +4 -1
  42. package/locales/it/review.json +4 -1
  43. package/locales/ja/review.json +4 -1
  44. package/locales/ko/review.json +4 -1
  45. package/locales/nl/review.json +4 -1
  46. package/locales/pl/review.json +4 -1
  47. package/locales/pt/review.json +4 -1
  48. package/locales/ro/review.json +4 -1
  49. package/locales/ru/review.json +4 -1
  50. package/locales/sk/review.json +4 -1
  51. package/locales/th/review.json +4 -1
  52. package/locales/tl/review.json +4 -1
  53. package/locales/tr/review.json +4 -1
  54. package/locales/uk/review.json +4 -1
  55. package/locales/vi/review.json +4 -1
  56. package/locales/zh/review.json +4 -1
  57. package/locales/zh_TW/review.json +4 -1
  58. package/package.json +5 -5
@@ -0,0 +1,11 @@
1
+ import { Dispatch } from 'redux';
2
+ import type { StoreState } from '../../reducers';
3
+ import type { Skill, ThunkOptions } from '../../types/common';
4
+ export declare const SKILL_FETCH_REQUEST: "@@skill/FETCH_REQUEST";
5
+ export declare const SKILL_FETCH_SUCCESS: "@@skill/FETCH_SUCCESS";
6
+ export declare const SKILL_FETCH_FAILURE: "@@skill/FETCH_FAILURE";
7
+ export declare type ReceivedSkill = {
8
+ type: typeof SKILL_FETCH_SUCCESS;
9
+ payload: Skill;
10
+ };
11
+ export declare const fetchSkill: (skillRef: string) => (dispatch: Dispatch, getState: () => StoreState, { services }: ThunkOptions) => ReceivedSkill;
@@ -0,0 +1,16 @@
1
+ import get from 'lodash/fp/get';
2
+ import buildTask from '@coorpacademy/redux-task';
3
+ export const SKILL_FETCH_REQUEST = '@@skill/FETCH_REQUEST';
4
+ export const SKILL_FETCH_SUCCESS = '@@skill/FETCH_SUCCESS';
5
+ export const SKILL_FETCH_FAILURE = '@@skill/FETCH_FAILURE';
6
+ export const fetchSkill = (skillRef) => (dispatch, getState, { services }) => {
7
+ const action = buildTask({
8
+ types: [SKILL_FETCH_REQUEST, SKILL_FETCH_SUCCESS, SKILL_FETCH_FAILURE],
9
+ task: () => {
10
+ const state = getState();
11
+ const token = get(['data', 'token'], state);
12
+ return services.fetchSkill(skillRef, token);
13
+ }
14
+ });
15
+ return dispatch(action);
16
+ };
@@ -1,6 +1,7 @@
1
1
  import buildTask from '@coorpacademy/redux-task';
2
2
  import get from 'lodash/fp/get';
3
3
  import { fetchSlide } from './fetch-slide';
4
+ import { fetchSkill } from './fetch-skill';
4
5
  export const POST_PROGRESSION_REQUEST = '@@progression/POST_REQUEST';
5
6
  export const POST_PROGRESSION_SUCCESS = '@@progression/POST_SUCCESS';
6
7
  export const POST_PROGRESSION_FAILURE = '@@progression/POST_FAILURE';
@@ -16,5 +17,6 @@ export const postProgression = (skillRef) => async (dispatch, getState, { servic
16
17
  const progression = response.payload;
17
18
  const slideRef = progression.state.nextContent.ref;
18
19
  await dispatch(fetchSlide(slideRef));
20
+ await dispatch(fetchSkill(skillRef));
19
21
  }
20
22
  };
package/es/index.js CHANGED
@@ -15,7 +15,7 @@ const ConnectedApp = (options) => {
15
15
  const props = {
16
16
  viewName: useSelector((state) => state.ui.navigation[state.ui.navigation.length - 1]),
17
17
  slides: useSelector((state) => mapStateToSlidesProps(state, dispatch, options)),
18
- skills: useSelector((state) => mapStateToSkillsProps(state)),
18
+ skills: useSelector((state) => mapStateToSkillsProps(state, options)),
19
19
  navigateBack: () => dispatch(navigateBack),
20
20
  onboarding: {}
21
21
  };
@@ -0,0 +1,5 @@
1
+ import { ReceivedSkill } from '../../actions/api/fetch-skill';
2
+ import { Skill } from '../../types/common';
3
+ export declare type CurrentSkillState = Skill | null;
4
+ declare const reducer: (state: CurrentSkillState | undefined, action: ReceivedSkill) => CurrentSkillState;
5
+ export default reducer;
@@ -0,0 +1,13 @@
1
+ import { SKILL_FETCH_SUCCESS } from '../../actions/api/fetch-skill';
2
+ const initialState = null;
3
+ const reducer = (
4
+ // eslint-disable-next-line default-param-last
5
+ state = initialState, action) => {
6
+ switch (action.type) {
7
+ case SKILL_FETCH_SUCCESS:
8
+ return action.payload;
9
+ default:
10
+ return state;
11
+ }
12
+ };
13
+ export default reducer;
@@ -4,6 +4,7 @@ import { SkillsState } from './skills';
4
4
  import { SlidesState } from './slides';
5
5
  import { TokenState } from './token';
6
6
  import { RankState } from './rank';
7
+ import { CurrentSkillState } from './current-skill';
7
8
  export declare type DataState = {
8
9
  corrections: CorrectionsState;
9
10
  progression: ProgressionState;
@@ -11,6 +12,7 @@ export declare type DataState = {
11
12
  slides: SlidesState;
12
13
  token: TokenState;
13
14
  rank: RankState;
15
+ currentSkill: CurrentSkillState;
14
16
  };
15
17
  declare const _default: import("redux").Reducer<import("redux").CombinedState<{
16
18
  corrections: CorrectionsState;
@@ -19,5 +21,6 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
19
21
  slides: SlidesState;
20
22
  token: string;
21
23
  rank: RankState;
22
- }>, import("../../actions/api/post-progression").FetchProgression | import("../../actions/api/post-progression").ReceivedProgression | import("./corrections").CorrectionsAction | import("../../actions/api/fetch-rank").RankAction | import("../../actions/api/post-answer").PostAnswerSuccessAction | import("../../actions/api/fetch-skills").ReceivedSkills | import("./slides").SlidesAction | import("../../actions/data/token").StoreToken>;
24
+ currentSkill: CurrentSkillState;
25
+ }>, import("../../actions/api/fetch-skill").ReceivedSkill | import("../../actions/api/post-progression").FetchProgression | import("../../actions/api/post-progression").ReceivedProgression | import("./corrections").CorrectionsAction | import("../../actions/api/fetch-rank").RankAction | import("../../actions/api/post-answer").PostAnswerSuccessAction | import("../../actions/api/fetch-skills").ReceivedSkills | import("./slides").SlidesAction | import("../../actions/data/token").StoreToken>;
23
26
  export default _default;
@@ -5,4 +5,13 @@ import skills from './skills';
5
5
  import slides from './slides';
6
6
  import token from './token';
7
7
  import rank from './rank';
8
- export default combineReducers({ corrections, progression, skills, slides, token, rank });
8
+ import currentSkill from './current-skill';
9
+ export default combineReducers({
10
+ corrections,
11
+ progression,
12
+ skills,
13
+ slides,
14
+ token,
15
+ rank,
16
+ currentSkill
17
+ });
@@ -12,6 +12,7 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
12
12
  slides: import("./data/slides").SlidesState;
13
13
  token: string;
14
14
  rank: import("./data/rank").RankState;
15
+ currentSkill: import("./data/current-skill").CurrentSkillState;
15
16
  }>;
16
17
  ui: import("redux").CombinedState<{
17
18
  currentSlideRef: string;
@@ -23,7 +24,7 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
23
24
  showButtonRevising: boolean;
24
25
  showCongrats: boolean;
25
26
  }>;
26
- }>, import("../actions/ui/slides").SetCurrentSlideAction | import("../actions/api/post-progression").FetchProgression | import("../actions/api/post-progression").ReceivedProgression | import("./data/corrections").CorrectionsAction | import("../actions/api/fetch-rank").RankAction | import("../actions/api/fetch-slides-to-review-by-skill-ref").ReceivedSlidesToReviewBySkillRef | import("../actions/api/post-answer").PostAnswerRequestAction | import("../actions/api/post-answer").PostAnswerSuccessAction | import("../actions/api/fetch-skills").ReceivedSkills | import("./data/slides").SlidesAction | import("../actions/data/token").StoreToken | import("../actions/ui/next-slide").NextSlideAction | import("../actions/ui/navigation").NavigateToAction | import("../actions/ui/navigation").NavigateBackAction | import("../actions/ui/answers").EditAnswerAction | {
27
+ }>, import("../actions/ui/slides").SetCurrentSlideAction | import("../actions/api/fetch-skill").ReceivedSkill | import("../actions/api/post-progression").FetchProgression | import("../actions/api/post-progression").ReceivedProgression | import("./data/corrections").CorrectionsAction | import("../actions/api/fetch-rank").RankAction | import("../actions/api/fetch-slides-to-review-by-skill-ref").ReceivedSlidesToReviewBySkillRef | import("../actions/api/post-answer").PostAnswerRequestAction | import("../actions/api/post-answer").PostAnswerSuccessAction | import("../actions/api/fetch-skills").ReceivedSkills | import("./data/slides").SlidesAction | import("../actions/data/token").StoreToken | import("../actions/ui/next-slide").NextSlideAction | import("../actions/ui/navigation").NavigateToAction | import("../actions/ui/navigation").NavigateBackAction | import("../actions/ui/answers").EditAnswerAction | {
27
28
  type: "@@ui/OPEN_POPIN";
28
29
  } | {
29
30
  type: "@@ui/CLOSE_POPIN";
@@ -6,5 +6,6 @@ export const fetchSkill = async (skillRef, token) => {
6
6
  const response = await crossFetch(`${host}/api/v2/skills?conditions={"ref":"${skillRef}"}`, {
7
7
  headers: { authorization: token }
8
8
  });
9
- return toJSON(response);
9
+ const skills = await toJSON(response);
10
+ return skills[0];
10
11
  };
@@ -1,4 +1,7 @@
1
1
  export declare type ViewName = 'skills' | 'onboarding' | 'slides' | 'loader';
2
+ export interface Translate {
3
+ (key: string, data?: Record<string, string>): string;
4
+ }
2
5
  export declare type ChoiceFromAPI = {
3
6
  _id: string;
4
7
  id?: string;
@@ -146,13 +149,13 @@ export declare type Options = {
146
149
  services: Services;
147
150
  };
148
151
  export declare type ConnectedOptions = {
149
- translate: (key: string, data?: unknown) => string;
152
+ translate: Translate;
150
153
  onQuitClick: () => void;
151
154
  };
152
155
  export declare type AppOptions = ConnectedOptions & {
153
156
  token: string;
154
157
  skillRef?: string;
155
- services: Services;
158
+ services?: Services;
156
159
  callbackOnViewChanged?: (viewName: ViewName) => void;
157
160
  };
158
161
  export declare type ThunkOptions = {
@@ -1,24 +1,4 @@
1
+ import { ReviewSkillsProps } from '@coorpacademy/components/es/template/app-review/skills/prop-types';
1
2
  import { StoreState } from '../../reducers';
2
- declare type SkillCard = {
3
- 'aria-label': string;
4
- skillTitle: string;
5
- skillAriaLabel: string;
6
- buttonLabel: string;
7
- buttonAriaLabel: string;
8
- reviseLabel: string;
9
- reviseAriaLabel: string;
10
- isCustom: boolean;
11
- onClick: () => void;
12
- };
13
- declare type NoSkillsProps = {
14
- iconSkillAriaLabel: string;
15
- };
16
- declare type SkillsProps = NoSkillsProps & {
17
- 'aria-label'?: string;
18
- title: string;
19
- isLoading?: boolean;
20
- isLoadingAriaLabel: string;
21
- listSkills: SkillCard[];
22
- };
23
- export { SkillsProps };
24
- export declare const mapStateToSkillsProps: (state: StoreState) => SkillsProps;
3
+ import type { ConnectedOptions } from '../../types/common';
4
+ export declare const mapStateToSkillsProps: (state: StoreState, options: ConnectedOptions) => ReviewSkillsProps;
@@ -1,20 +1,26 @@
1
- export const mapStateToSkillsProps = (state) => {
1
+ export const mapStateToSkillsProps = (state, options) => {
2
+ const { translate } = options;
2
3
  return {
3
- title: '@todo title',
4
- iconSkillAriaLabel: '@todo iconSkillAriaLabel',
4
+ 'aria-label': translate('Review Skills Container'),
5
+ title: translate('Skills you can review'),
5
6
  isLoading: false,
6
- isLoadingAriaLabel: '@todo loading',
7
+ isLoadingAriaLabel: 'Review skills container is loading',
7
8
  listSkills: state.data.skills.map(skill => ({
8
- 'aria-label': '',
9
+ 'aria-label': translate('Skill Card'),
9
10
  isCustom: skill.custom,
10
11
  skillTitle: skill.name,
11
- skillAriaLabel: '@todo skill aria label',
12
- buttonLabel: '@todo button',
13
- buttonAriaLabel: '@todo button aria label',
14
- reviseLabel: '@todo revise',
15
- reviseAriaLabel: '@todo revise aria label',
12
+ skillAriaLabel: skill.name,
13
+ buttonLabel: translate('Review this skill'),
14
+ buttonAriaLabel: translate('Review this skill'),
15
+ reviseLabel: translate('{{count}} questions to review', { count: `${skill.slidesToReview}` }),
16
+ reviseAriaLabel: translate('{{count}} questions to review', {
17
+ count: `${skill.slidesToReview}`
18
+ }),
16
19
  // eslint-disable-next-line no-console
17
20
  onClick: () => console.log('@todo plug dispatcher select skill')
18
- }))
21
+ })),
22
+ titleNoSkills: translate('No skill to revise'),
23
+ textNoSkills: translate('Complete courses before revising'),
24
+ iconSkillAriaLabel: 'Image without information'
19
25
  };
20
26
  };
@@ -60,7 +60,11 @@ const getCurrentSlideRef = (state) => {
60
60
  const content = progression.state.content;
61
61
  return content.ref;
62
62
  };
63
- const buildStackSlides = (state, dispatch) => {
63
+ const isLastSlideAnswered = (slidesRef, slideRef) => {
64
+ return last(slidesRef) === slideRef;
65
+ };
66
+ const buildStackSlides = (state, dispatch, options) => {
67
+ const { translate } = options;
64
68
  const currentSlideRef = getCurrentSlideRef(state);
65
69
  const progression = state.data.progression;
66
70
  if (!currentSlideRef || !progression)
@@ -69,22 +73,25 @@ const buildStackSlides = (state, dispatch) => {
69
73
  // @ts-expect-error typescript does not support capped versions of lodash functions
70
74
  const stack = reduce.convert({ cap: false })((acc, uiSlide, _index) => {
71
75
  const index = toInteger(_index);
72
- const positions = state.ui.positions;
73
- const position = positions[index];
74
76
  const slideRef = slideRefs[index];
77
+ const lastAnsweredSlideRef = isLastSlideAnswered(progression.state.slides, slideRef);
78
+ const positions = state.ui.positions;
79
+ // when unstack the last answered slide (position -1), we set the position to 0 only during the animation
80
+ // to avoid to hide the slide (caused by the position -1).
81
+ const position = lastAnsweredSlideRef && positions[index] === -1 ? 0 : positions[index];
75
82
  if (!slideRef)
76
83
  return set(index, { ...uiSlide, position }, acc);
77
84
  const slideFromAPI = get(slideRef, state.data.slides);
78
85
  if (!slideFromAPI)
79
86
  return set(index, { ...uiSlide, position }, acc);
80
87
  const answers = getOr([], ['ui', 'answers', slideRef], state);
81
- const { questionText, answerUI } = mapApiSlideToUi(dispatch)(slideFromAPI, answers);
88
+ const { questionText, answerUI } = mapApiSlideToUi(dispatch, translate)(slideFromAPI, answers);
82
89
  const { title: parentContentTitle, type: parentContentType } = slideFromAPI.parentContentTitle;
83
90
  const isCurrentSlideRef = currentSlideRef === slideRef;
84
91
  const slideUI = get(['ui', 'slide', slideRef], state);
85
92
  const animateCorrectionPopin = isCurrentSlideRef && slideUI.animateCorrectionPopin;
86
93
  const showCorrectionPopin = isCurrentSlideRef && slideUI.showCorrectionPopin;
87
- const animationType = slideUI.animationType;
94
+ const animationType = lastAnsweredSlideRef ? slideUI.animationType : undefined;
88
95
  const updatedUiSlide = {
89
96
  ...uiSlide,
90
97
  position,
@@ -93,7 +100,10 @@ const buildStackSlides = (state, dispatch) => {
93
100
  loading: false,
94
101
  questionText,
95
102
  answerUI,
96
- parentContentTitle: `From "${parentContentTitle}" ${parentContentType}`,
103
+ parentContentTitle: translate('Content Parent Title', {
104
+ contentTitle: parentContentTitle,
105
+ contentType: parentContentType
106
+ }),
97
107
  animationType
98
108
  };
99
109
  return set(index, updatedUiSlide, acc);
@@ -167,7 +177,8 @@ export const buildStepItems = (state) => {
167
177
  });
168
178
  return steps;
169
179
  };
170
- const getCorrectionPopinProps = (dispatch) => (isCorrect, correctAnswer, klf, translate) => {
180
+ const getCorrectionPopinProps = (dispatch) => (isCorrect, correctAnswer, klf, translate, endReview) => {
181
+ const nextLabel = endReview ? translate('Continue') : translate('Next Question');
171
182
  return {
172
183
  klf: isCorrect
173
184
  ? undefined
@@ -178,11 +189,11 @@ const getCorrectionPopinProps = (dispatch) => (isCorrect, correctAnswer, klf, tr
178
189
  resultLabel: isCorrect ? translate('Correct Answer') : translate('Wrong Answer'),
179
190
  information: {
180
191
  label: isCorrect ? translate('KLF') : translate('Correct Answer'),
181
- message: isCorrect ? klf : join(',', correctAnswer)
192
+ message: isCorrect ? klf : join(', ', correctAnswer)
182
193
  },
183
194
  next: {
184
- 'aria-label': translate('Next Question'),
185
- label: translate('Next Question'),
195
+ 'aria-label': nextLabel,
196
+ label: nextLabel,
186
197
  onClick: () => {
187
198
  dispatch(nextSlide);
188
199
  }
@@ -309,10 +320,11 @@ export const mapStateToSlidesProps = (state, dispatch, options) => {
309
320
  const klf = getOr('', ['data', 'slides', currentSlideRef, 'klf'], state);
310
321
  const showQuitPopin = get(['ui', 'showQuitPopin'], state);
311
322
  const showCongrats = get(['ui', 'showCongrats'], state);
323
+ const skillName = getOr('', ['data', 'currentSkill', 'name'], state);
312
324
  return {
313
325
  header: {
314
326
  mode: translate('Review Title'),
315
- skillName: '__agility',
327
+ skillName,
316
328
  onQuitClick: () => dispatch(openQuitPopin),
317
329
  'aria-label': 'aria-header-wrapper',
318
330
  closeButtonAriaLabel: 'aria-close-button',
@@ -320,7 +332,7 @@ export const mapStateToSlidesProps = (state, dispatch, options) => {
320
332
  hiddenSteps: showCongrats
321
333
  },
322
334
  stack: {
323
- slides: buildStackSlides(state, dispatch),
335
+ slides: buildStackSlides(state, dispatch, options),
324
336
  validateButton: {
325
337
  label: translate('Validate'),
326
338
  disabled: !get(['ui', 'slide', currentSlideRef, 'validateButton'], state),
@@ -329,7 +341,7 @@ export const mapStateToSlidesProps = (state, dispatch, options) => {
329
341
  }
330
342
  },
331
343
  correctionPopinProps: correction &&
332
- getCorrectionPopinProps(dispatch)(isCorrect, correction.correctAnswer, klf, translate),
344
+ getCorrectionPopinProps(dispatch)(isCorrect, correction.correctAnswer, klf, translate, endReview),
333
345
  endReview: endReview && state.ui.showCongrats
334
346
  },
335
347
  congrats: buildCongratsProps(state, dispatch, options),
@@ -1,8 +1,8 @@
1
1
  import { Dispatch } from 'redux';
2
2
  import { AnswerUI } from '../../types/slides';
3
- import { Question, SlideFromAPI } from '../../types/common';
3
+ import { Question, SlideFromAPI, Translate } from '../../types/common';
4
4
  export declare const getQuestionType: (question: Question) => Question['type'];
5
- export declare const mapApiSlideToUi: (dispatch: Dispatch) => (slide: SlideFromAPI, answers: string[]) => {
5
+ export declare const mapApiSlideToUi: (dispatch: Dispatch, translate: Translate) => (slide: SlideFromAPI, answers: string[]) => {
6
6
  questionText: string;
7
7
  answerUI: AnswerUI;
8
8
  };
@@ -54,11 +54,11 @@ const updateTemplateAnswer = (text, _answers, index, max) => {
54
54
  const answers = isEmpty(_answers) ? times(constant(undefined), max) : _answers;
55
55
  return map(a => (isNil(a) ? '' : a), set(index, text, answers));
56
56
  };
57
- const templateTextProps = (dispatch, answers, choice, index, maxLength) => {
57
+ const templateTextProps = (dispatch, translate, answers, choice, index, maxLength) => {
58
58
  return {
59
59
  type: 'text',
60
60
  name: getOr('', 'name', choice),
61
- placeholder: 'Type here',
61
+ placeholder: translate('Type here'),
62
62
  value: get(index, answers),
63
63
  onChange: (text) => {
64
64
  const newAnswers = updateTemplateAnswer(text, answers, index, maxLength);
@@ -66,10 +66,10 @@ const templateTextProps = (dispatch, answers, choice, index, maxLength) => {
66
66
  }
67
67
  };
68
68
  };
69
- const templateSelectProps = (dispatch, answers, choice, index, maxLength) => {
69
+ const templateSelectProps = (dispatch, translate, answers, choice, index, maxLength) => {
70
70
  const answer = get(index, answers);
71
71
  const temporaryOption = {
72
- name: 'Select an answer',
72
+ name: translate('Select an answer'),
73
73
  value: '',
74
74
  validOption: false,
75
75
  selected: true
@@ -93,15 +93,15 @@ const templateSelectProps = (dispatch, answers, choice, index, maxLength) => {
93
93
  options: isEmpty(answer) ? concat([temporaryOption], selectOptions) : selectOptions
94
94
  };
95
95
  };
96
- const templateProps = (dispatch) => (answers, question) => {
96
+ const templateProps = (dispatch, translate) => (answers, question) => {
97
97
  const choices = question.content.choices;
98
98
  const maxLength = size(choices);
99
99
  return {
100
100
  type: 'template',
101
101
  template: get('content.template', question),
102
102
  answers: choices.map((choice, index) => choice.type === 'text'
103
- ? templateTextProps(dispatch, answers, choice, index, maxLength)
104
- : templateSelectProps(dispatch, answers, choice, index, maxLength))
103
+ ? templateTextProps(dispatch, translate, answers, choice, index, maxLength)
104
+ : templateSelectProps(dispatch, translate, answers, choice, index, maxLength))
105
105
  };
106
106
  };
107
107
  const basicProps = (dispatch) => (answers, question) => {
@@ -144,7 +144,7 @@ const sliderProps = (dispatch) => (answers, question) => {
144
144
  };
145
145
  export const getQuestionType = (question) => question.type;
146
146
  const getHelp = (slide) => get('question.explanation', slide);
147
- const getAnswerUIModel = (question, answers, dispatch) => {
147
+ const getAnswerUIModel = (question, answers, dispatch, translate) => {
148
148
  const type = getQuestionType(question);
149
149
  switch (type) {
150
150
  case 'qcm':
@@ -156,17 +156,20 @@ const getAnswerUIModel = (question, answers, dispatch) => {
156
156
  case 'basic':
157
157
  return basicProps(dispatch)(answers, question);
158
158
  case 'template':
159
- return templateProps(dispatch)(answers, question);
159
+ return templateProps(dispatch, translate)(answers, question);
160
160
  case 'slider':
161
161
  return sliderProps(dispatch)(answers, question);
162
162
  default:
163
163
  throw new Error(`${type} is not an handled question.type`);
164
164
  }
165
165
  };
166
- export const mapApiSlideToUi = (dispatch) => (slide, answers) => {
166
+ export const mapApiSlideToUi = (dispatch, translate) => (slide, answers) => {
167
167
  const questionText = getOr('', 'question.header', slide);
168
168
  return {
169
169
  questionText,
170
- answerUI: { model: getAnswerUIModel(slide.question, answers, dispatch), help: getHelp(slide) }
170
+ answerUI: {
171
+ model: getAnswerUIModel(slide.question, answers, dispatch, translate),
172
+ help: getHelp(slide)
173
+ }
171
174
  };
172
175
  };
@@ -0,0 +1,11 @@
1
+ import { Dispatch } from 'redux';
2
+ import type { StoreState } from '../../reducers';
3
+ import type { Skill, ThunkOptions } from '../../types/common';
4
+ export declare const SKILL_FETCH_REQUEST: "@@skill/FETCH_REQUEST";
5
+ export declare const SKILL_FETCH_SUCCESS: "@@skill/FETCH_SUCCESS";
6
+ export declare const SKILL_FETCH_FAILURE: "@@skill/FETCH_FAILURE";
7
+ export declare type ReceivedSkill = {
8
+ type: typeof SKILL_FETCH_SUCCESS;
9
+ payload: Skill;
10
+ };
11
+ export declare const fetchSkill: (skillRef: string) => (dispatch: Dispatch, getState: () => StoreState, { services }: ThunkOptions) => ReceivedSkill;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchSkill = exports.SKILL_FETCH_FAILURE = exports.SKILL_FETCH_SUCCESS = exports.SKILL_FETCH_REQUEST = void 0;
7
+ const get_1 = __importDefault(require("lodash/fp/get"));
8
+ const redux_task_1 = __importDefault(require("@coorpacademy/redux-task"));
9
+ exports.SKILL_FETCH_REQUEST = '@@skill/FETCH_REQUEST';
10
+ exports.SKILL_FETCH_SUCCESS = '@@skill/FETCH_SUCCESS';
11
+ exports.SKILL_FETCH_FAILURE = '@@skill/FETCH_FAILURE';
12
+ const fetchSkill = (skillRef) => (dispatch, getState, { services }) => {
13
+ const action = (0, redux_task_1.default)({
14
+ types: [exports.SKILL_FETCH_REQUEST, exports.SKILL_FETCH_SUCCESS, exports.SKILL_FETCH_FAILURE],
15
+ task: () => {
16
+ const state = getState();
17
+ const token = (0, get_1.default)(['data', 'token'], state);
18
+ return services.fetchSkill(skillRef, token);
19
+ }
20
+ });
21
+ return dispatch(action);
22
+ };
23
+ exports.fetchSkill = fetchSkill;
@@ -7,6 +7,7 @@ exports.postProgression = exports.POST_PROGRESSION_FAILURE = exports.POST_PROGRE
7
7
  const redux_task_1 = __importDefault(require("@coorpacademy/redux-task"));
8
8
  const get_1 = __importDefault(require("lodash/fp/get"));
9
9
  const fetch_slide_1 = require("./fetch-slide");
10
+ const fetch_skill_1 = require("./fetch-skill");
10
11
  exports.POST_PROGRESSION_REQUEST = '@@progression/POST_REQUEST';
11
12
  exports.POST_PROGRESSION_SUCCESS = '@@progression/POST_SUCCESS';
12
13
  exports.POST_PROGRESSION_FAILURE = '@@progression/POST_FAILURE';
@@ -22,6 +23,7 @@ const postProgression = (skillRef) => async (dispatch, getState, { services }) =
22
23
  const progression = response.payload;
23
24
  const slideRef = progression.state.nextContent.ref;
24
25
  await dispatch((0, fetch_slide_1.fetchSlide)(slideRef));
26
+ await dispatch((0, fetch_skill_1.fetchSkill)(skillRef));
25
27
  }
26
28
  };
27
29
  exports.postProgression = postProgression;
package/lib/index.js CHANGED
@@ -43,7 +43,7 @@ const ConnectedApp = (options) => {
43
43
  const props = {
44
44
  viewName: (0, react_redux_1.useSelector)((state) => state.ui.navigation[state.ui.navigation.length - 1]),
45
45
  slides: (0, react_redux_1.useSelector)((state) => (0, slides_1.mapStateToSlidesProps)(state, dispatch, options)),
46
- skills: (0, react_redux_1.useSelector)((state) => (0, skills_1.mapStateToSkillsProps)(state)),
46
+ skills: (0, react_redux_1.useSelector)((state) => (0, skills_1.mapStateToSkillsProps)(state, options)),
47
47
  navigateBack: () => dispatch(navigation_1.navigateBack),
48
48
  onboarding: {}
49
49
  };
@@ -0,0 +1,5 @@
1
+ import { ReceivedSkill } from '../../actions/api/fetch-skill';
2
+ import { Skill } from '../../types/common';
3
+ export declare type CurrentSkillState = Skill | null;
4
+ declare const reducer: (state: CurrentSkillState | undefined, action: ReceivedSkill) => CurrentSkillState;
5
+ export default reducer;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fetch_skill_1 = require("../../actions/api/fetch-skill");
4
+ const initialState = null;
5
+ const reducer = (
6
+ // eslint-disable-next-line default-param-last
7
+ state = initialState, action) => {
8
+ switch (action.type) {
9
+ case fetch_skill_1.SKILL_FETCH_SUCCESS:
10
+ return action.payload;
11
+ default:
12
+ return state;
13
+ }
14
+ };
15
+ exports.default = reducer;
@@ -4,6 +4,7 @@ import { SkillsState } from './skills';
4
4
  import { SlidesState } from './slides';
5
5
  import { TokenState } from './token';
6
6
  import { RankState } from './rank';
7
+ import { CurrentSkillState } from './current-skill';
7
8
  export declare type DataState = {
8
9
  corrections: CorrectionsState;
9
10
  progression: ProgressionState;
@@ -11,6 +12,7 @@ export declare type DataState = {
11
12
  slides: SlidesState;
12
13
  token: TokenState;
13
14
  rank: RankState;
15
+ currentSkill: CurrentSkillState;
14
16
  };
15
17
  declare const _default: import("redux").Reducer<import("redux").CombinedState<{
16
18
  corrections: CorrectionsState;
@@ -19,5 +21,6 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
19
21
  slides: SlidesState;
20
22
  token: string;
21
23
  rank: RankState;
22
- }>, import("../../actions/api/post-progression").FetchProgression | import("../../actions/api/post-progression").ReceivedProgression | import("./corrections").CorrectionsAction | import("../../actions/api/fetch-rank").RankAction | import("../../actions/api/post-answer").PostAnswerSuccessAction | import("../../actions/api/fetch-skills").ReceivedSkills | import("./slides").SlidesAction | import("../../actions/data/token").StoreToken>;
24
+ currentSkill: CurrentSkillState;
25
+ }>, import("../../actions/api/fetch-skill").ReceivedSkill | import("../../actions/api/post-progression").FetchProgression | import("../../actions/api/post-progression").ReceivedProgression | import("./corrections").CorrectionsAction | import("../../actions/api/fetch-rank").RankAction | import("../../actions/api/post-answer").PostAnswerSuccessAction | import("../../actions/api/fetch-skills").ReceivedSkills | import("./slides").SlidesAction | import("../../actions/data/token").StoreToken>;
23
26
  export default _default;
@@ -10,4 +10,13 @@ const skills_1 = __importDefault(require("./skills"));
10
10
  const slides_1 = __importDefault(require("./slides"));
11
11
  const token_1 = __importDefault(require("./token"));
12
12
  const rank_1 = __importDefault(require("./rank"));
13
- exports.default = (0, redux_1.combineReducers)({ corrections: corrections_1.default, progression: progression_1.default, skills: skills_1.default, slides: slides_1.default, token: token_1.default, rank: rank_1.default });
13
+ const current_skill_1 = __importDefault(require("./current-skill"));
14
+ exports.default = (0, redux_1.combineReducers)({
15
+ corrections: corrections_1.default,
16
+ progression: progression_1.default,
17
+ skills: skills_1.default,
18
+ slides: slides_1.default,
19
+ token: token_1.default,
20
+ rank: rank_1.default,
21
+ currentSkill: current_skill_1.default
22
+ });
@@ -12,6 +12,7 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
12
12
  slides: import("./data/slides").SlidesState;
13
13
  token: string;
14
14
  rank: import("./data/rank").RankState;
15
+ currentSkill: import("./data/current-skill").CurrentSkillState;
15
16
  }>;
16
17
  ui: import("redux").CombinedState<{
17
18
  currentSlideRef: string;
@@ -23,7 +24,7 @@ declare const _default: import("redux").Reducer<import("redux").CombinedState<{
23
24
  showButtonRevising: boolean;
24
25
  showCongrats: boolean;
25
26
  }>;
26
- }>, import("../actions/ui/slides").SetCurrentSlideAction | import("../actions/api/post-progression").FetchProgression | import("../actions/api/post-progression").ReceivedProgression | import("./data/corrections").CorrectionsAction | import("../actions/api/fetch-rank").RankAction | import("../actions/api/fetch-slides-to-review-by-skill-ref").ReceivedSlidesToReviewBySkillRef | import("../actions/api/post-answer").PostAnswerRequestAction | import("../actions/api/post-answer").PostAnswerSuccessAction | import("../actions/api/fetch-skills").ReceivedSkills | import("./data/slides").SlidesAction | import("../actions/data/token").StoreToken | import("../actions/ui/next-slide").NextSlideAction | import("../actions/ui/navigation").NavigateToAction | import("../actions/ui/navigation").NavigateBackAction | import("../actions/ui/answers").EditAnswerAction | {
27
+ }>, import("../actions/ui/slides").SetCurrentSlideAction | import("../actions/api/fetch-skill").ReceivedSkill | import("../actions/api/post-progression").FetchProgression | import("../actions/api/post-progression").ReceivedProgression | import("./data/corrections").CorrectionsAction | import("../actions/api/fetch-rank").RankAction | import("../actions/api/fetch-slides-to-review-by-skill-ref").ReceivedSlidesToReviewBySkillRef | import("../actions/api/post-answer").PostAnswerRequestAction | import("../actions/api/post-answer").PostAnswerSuccessAction | import("../actions/api/fetch-skills").ReceivedSkills | import("./data/slides").SlidesAction | import("../actions/data/token").StoreToken | import("../actions/ui/next-slide").NextSlideAction | import("../actions/ui/navigation").NavigateToAction | import("../actions/ui/navigation").NavigateBackAction | import("../actions/ui/answers").EditAnswerAction | {
27
28
  type: "@@ui/OPEN_POPIN";
28
29
  } | {
29
30
  type: "@@ui/CLOSE_POPIN";
@@ -12,6 +12,7 @@ const fetchSkill = async (skillRef, token) => {
12
12
  const response = await (0, cross_fetch_1.default)(`${host}/api/v2/skills?conditions={"ref":"${skillRef}"}`, {
13
13
  headers: { authorization: token }
14
14
  });
15
- return (0, fetch_responses_1.toJSON)(response);
15
+ const skills = await (0, fetch_responses_1.toJSON)(response);
16
+ return skills[0];
16
17
  };
17
18
  exports.fetchSkill = fetchSkill;
@@ -1,4 +1,7 @@
1
1
  export declare type ViewName = 'skills' | 'onboarding' | 'slides' | 'loader';
2
+ export interface Translate {
3
+ (key: string, data?: Record<string, string>): string;
4
+ }
2
5
  export declare type ChoiceFromAPI = {
3
6
  _id: string;
4
7
  id?: string;
@@ -146,13 +149,13 @@ export declare type Options = {
146
149
  services: Services;
147
150
  };
148
151
  export declare type ConnectedOptions = {
149
- translate: (key: string, data?: unknown) => string;
152
+ translate: Translate;
150
153
  onQuitClick: () => void;
151
154
  };
152
155
  export declare type AppOptions = ConnectedOptions & {
153
156
  token: string;
154
157
  skillRef?: string;
155
- services: Services;
158
+ services?: Services;
156
159
  callbackOnViewChanged?: (viewName: ViewName) => void;
157
160
  };
158
161
  export declare type ThunkOptions = {