@magmamath/students-features 1.3.10-rc.0 → 1.3.10

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 (97) hide show
  1. package/dist/commonjs/features/uiMode/getUIMode.js +47 -0
  2. package/dist/commonjs/features/uiMode/getUIMode.js.map +1 -0
  3. package/dist/commonjs/features/uiMode/index.js +20 -0
  4. package/dist/commonjs/features/uiMode/index.js.map +1 -0
  5. package/dist/commonjs/features/uiMode/uiMode.constants.js +14 -0
  6. package/dist/commonjs/features/uiMode/uiMode.constants.js.map +1 -0
  7. package/dist/commonjs/features/uiMode/uiMode.helpers.js +53 -0
  8. package/dist/commonjs/features/uiMode/uiMode.helpers.js.map +1 -0
  9. package/dist/commonjs/features/uiMode/uiMode.types.js +6 -0
  10. package/dist/commonjs/features/uiMode/uiMode.types.js.map +1 -0
  11. package/dist/commonjs/index.js +12 -0
  12. package/dist/commonjs/index.js.map +1 -1
  13. package/dist/module/features/uiMode/getUIMode.js +42 -0
  14. package/dist/module/features/uiMode/getUIMode.js.map +1 -0
  15. package/dist/module/features/uiMode/index.js +5 -0
  16. package/dist/module/features/uiMode/index.js.map +1 -0
  17. package/dist/module/features/uiMode/uiMode.constants.js +10 -0
  18. package/dist/module/features/uiMode/uiMode.constants.js.map +1 -0
  19. package/dist/module/features/uiMode/uiMode.helpers.js +45 -0
  20. package/dist/module/features/uiMode/uiMode.helpers.js.map +1 -0
  21. package/dist/module/features/uiMode/uiMode.types.js +4 -0
  22. package/dist/module/features/uiMode/uiMode.types.js.map +1 -0
  23. package/dist/module/index.js +1 -0
  24. package/dist/module/index.js.map +1 -1
  25. package/dist/typescript/commonjs/features/uiMode/__tests__/getUIMode.test.d.ts +2 -0
  26. package/dist/typescript/commonjs/features/uiMode/__tests__/getUIMode.test.d.ts.map +1 -0
  27. package/dist/typescript/commonjs/features/uiMode/getUIMode.d.ts +3 -0
  28. package/dist/typescript/commonjs/features/uiMode/getUIMode.d.ts.map +1 -0
  29. package/dist/typescript/commonjs/features/uiMode/index.d.ts +3 -0
  30. package/dist/typescript/commonjs/features/uiMode/index.d.ts.map +1 -0
  31. package/dist/typescript/commonjs/features/uiMode/uiMode.constants.d.ts +7 -0
  32. package/dist/typescript/commonjs/features/uiMode/uiMode.constants.d.ts.map +1 -0
  33. package/dist/typescript/commonjs/features/uiMode/uiMode.helpers.d.ts +8 -0
  34. package/dist/typescript/commonjs/features/uiMode/uiMode.helpers.d.ts.map +1 -0
  35. package/dist/typescript/commonjs/features/uiMode/uiMode.types.d.ts +57 -0
  36. package/dist/typescript/commonjs/features/uiMode/uiMode.types.d.ts.map +1 -0
  37. package/dist/typescript/commonjs/index.d.ts +1 -0
  38. package/dist/typescript/commonjs/index.d.ts.map +1 -1
  39. package/dist/typescript/module/features/uiMode/__tests__/getUIMode.test.d.ts +2 -0
  40. package/dist/typescript/module/features/uiMode/__tests__/getUIMode.test.d.ts.map +1 -0
  41. package/dist/typescript/module/features/uiMode/getUIMode.d.ts +3 -0
  42. package/dist/typescript/module/features/uiMode/getUIMode.d.ts.map +1 -0
  43. package/dist/typescript/module/features/uiMode/index.d.ts +3 -0
  44. package/dist/typescript/module/features/uiMode/index.d.ts.map +1 -0
  45. package/dist/typescript/module/features/uiMode/uiMode.constants.d.ts +7 -0
  46. package/dist/typescript/module/features/uiMode/uiMode.constants.d.ts.map +1 -0
  47. package/dist/typescript/module/features/uiMode/uiMode.helpers.d.ts +8 -0
  48. package/dist/typescript/module/features/uiMode/uiMode.helpers.d.ts.map +1 -0
  49. package/dist/typescript/module/features/uiMode/uiMode.types.d.ts +57 -0
  50. package/dist/typescript/module/features/uiMode/uiMode.types.d.ts.map +1 -0
  51. package/dist/typescript/module/index.d.ts +1 -0
  52. package/dist/typescript/module/index.d.ts.map +1 -1
  53. package/package.json +2 -2
  54. package/src/features/uiMode/__tests__/SPEC.md +114 -0
  55. package/src/features/uiMode/__tests__/getUIMode.test.ts +364 -0
  56. package/src/features/uiMode/getUIMode.ts +28 -0
  57. package/src/features/uiMode/index.ts +2 -0
  58. package/src/features/uiMode/uiMode.constants.ts +7 -0
  59. package/src/features/uiMode/uiMode.helpers.ts +52 -0
  60. package/src/features/uiMode/uiMode.types.ts +46 -0
  61. package/src/index.ts +1 -0
  62. package/dist/commonjs/features/interfaceMode/index.js +0 -33
  63. package/dist/commonjs/features/interfaceMode/index.js.map +0 -1
  64. package/dist/commonjs/features/interfaceMode/interfaceMode.constants.js +0 -30
  65. package/dist/commonjs/features/interfaceMode/interfaceMode.constants.js.map +0 -1
  66. package/dist/commonjs/features/interfaceMode/interfaceMode.helpers.js +0 -56
  67. package/dist/commonjs/features/interfaceMode/interfaceMode.helpers.js.map +0 -1
  68. package/dist/commonjs/features/interfaceMode/model/InterfaceModeModel.js +0 -110
  69. package/dist/commonjs/features/interfaceMode/model/InterfaceModeModel.js.map +0 -1
  70. package/dist/module/features/interfaceMode/index.js +0 -6
  71. package/dist/module/features/interfaceMode/index.js.map +0 -1
  72. package/dist/module/features/interfaceMode/interfaceMode.constants.js +0 -26
  73. package/dist/module/features/interfaceMode/interfaceMode.constants.js.map +0 -1
  74. package/dist/module/features/interfaceMode/interfaceMode.helpers.js +0 -48
  75. package/dist/module/features/interfaceMode/interfaceMode.helpers.js.map +0 -1
  76. package/dist/module/features/interfaceMode/model/InterfaceModeModel.js +0 -105
  77. package/dist/module/features/interfaceMode/model/InterfaceModeModel.js.map +0 -1
  78. package/dist/typescript/commonjs/features/interfaceMode/index.d.ts +0 -4
  79. package/dist/typescript/commonjs/features/interfaceMode/index.d.ts.map +0 -1
  80. package/dist/typescript/commonjs/features/interfaceMode/interfaceMode.constants.d.ts +0 -22
  81. package/dist/typescript/commonjs/features/interfaceMode/interfaceMode.constants.d.ts.map +0 -1
  82. package/dist/typescript/commonjs/features/interfaceMode/interfaceMode.helpers.d.ts +0 -28
  83. package/dist/typescript/commonjs/features/interfaceMode/interfaceMode.helpers.d.ts.map +0 -1
  84. package/dist/typescript/commonjs/features/interfaceMode/model/InterfaceModeModel.d.ts +0 -33
  85. package/dist/typescript/commonjs/features/interfaceMode/model/InterfaceModeModel.d.ts.map +0 -1
  86. package/dist/typescript/module/features/interfaceMode/index.d.ts +0 -4
  87. package/dist/typescript/module/features/interfaceMode/index.d.ts.map +0 -1
  88. package/dist/typescript/module/features/interfaceMode/interfaceMode.constants.d.ts +0 -22
  89. package/dist/typescript/module/features/interfaceMode/interfaceMode.constants.d.ts.map +0 -1
  90. package/dist/typescript/module/features/interfaceMode/interfaceMode.helpers.d.ts +0 -28
  91. package/dist/typescript/module/features/interfaceMode/interfaceMode.helpers.d.ts.map +0 -1
  92. package/dist/typescript/module/features/interfaceMode/model/InterfaceModeModel.d.ts +0 -33
  93. package/dist/typescript/module/features/interfaceMode/model/InterfaceModeModel.d.ts.map +0 -1
  94. package/src/features/interfaceMode/index.ts +0 -3
  95. package/src/features/interfaceMode/interfaceMode.constants.ts +0 -24
  96. package/src/features/interfaceMode/interfaceMode.helpers.ts +0 -79
  97. package/src/features/interfaceMode/model/InterfaceModeModel.ts +0 -115
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magmamath/students-features",
3
- "version": "1.3.10-rc.0",
3
+ "version": "1.3.10",
4
4
  "description": "Magmamath features library",
5
5
  "source": "src/index.ts",
6
6
  "main": "src/index.ts",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@magmamath/frontend-config": "1.1.3",
44
- "@magmamath/react-native-draw-board": "1.8.2-rc.3",
44
+ "@magmamath/react-native-draw-board": "1.8.2",
45
45
  "@magmamath/react-native-ui": "0.4.83",
46
46
  "@matteappen/skills-utils": "^3.7.1",
47
47
  "@react-native-masked-view/masked-view": "^0.3.2",
@@ -0,0 +1,114 @@
1
+ # UIMode Specification
2
+
3
+ ## Inputs
4
+
5
+ | Input | Type | Description |
6
+ |----------------------|-------------------|---------------------------------------------------|
7
+ | `user.grade` | `number \| null` | User's grade level. Invalid when `null` or `-1` |
8
+ | `practice.isEnabled` | `boolean` | Whether this is a practice exercise |
9
+ | `practice.grade` | `number \| null` | Grade of the practice problem |
10
+ | `assignment.grade` | `number \| null` | From `assignment.classes[0].grade` |
11
+ | `locale` | `Locale` | e.g. `US`, `CA`, `SE` |
12
+ | `problem.answerType` | `AnswerType` | Current problem's answer type |
13
+ | `problem.characterType` | `number` | Current problem's character type |
14
+ | `problem.hasAnswerVariants` | `boolean` | Whether the current problem has answer variants |
15
+
16
+ ## Output
17
+
18
+ | Field | Type | Values |
19
+ |--------------|------------------|---------------------------------|
20
+ | `general` | `UIMode` | `SIMPLE` or `REGULAR` |
21
+ | `toolbar` | `ToolBarVariants` | `SIMPLE`, `COMMON`, `ADVANCED` |
22
+ | `answerArea` | `UIMode` | `SIMPLE` or `REGULAR` |
23
+
24
+ ---
25
+
26
+ ## Step 1: Determine `isSimpleMode`
27
+
28
+ A grade is "simple" when it is **not null** and is **between 0 and 2 inclusive**.
29
+
30
+ | Condition | Grade used |
31
+ |------------------------------------|----------------------|
32
+ | `practice.isEnabled` is `true` | `practice.grade` |
33
+ | `user.grade` is valid (not null/-1)| `user.grade` |
34
+ | `user.grade` is null or -1 | `assignment.grade` |
35
+
36
+ ### Test cases
37
+
38
+ | # | practice.isEnabled | practice.grade | user.grade | assignment.grade | isSimpleMode |
39
+ |----|--------------------|----------------|------------|------------------|--------------|
40
+ | 1 | true | 0 | - | - | true |
41
+ | 2 | true | 2 | - | - | true |
42
+ | 3 | true | 3 | - | - | false |
43
+ | 4 | true | null | - | - | false |
44
+ | 5 | false | - | 1 | - | true |
45
+ | 6 | false | - | 5 | - | false |
46
+ | 7 | false | - | null | 2 | true |
47
+ | 8 | false | - | -1 | 2 | true |
48
+ | 9 | false | - | null | 5 | false |
49
+ | 10 | false | - | null | null | false |
50
+
51
+ ---
52
+
53
+ ## Step 2: `general`
54
+
55
+ | isSimpleMode | general |
56
+ |--------------|-----------|
57
+ | true | `SIMPLE` |
58
+ | false | `REGULAR` |
59
+
60
+ ---
61
+
62
+ ## Step 3: `toolbar`
63
+
64
+ Effective grade = `assignment.grade ?? practice.grade`
65
+
66
+ | # | assignment.grade | practice.grade | locale | isSimpleMode | toolbar |
67
+ |----|------------------|----------------|--------|--------------|------------|
68
+ | 11 | 7 | - | SE | any | `ADVANCED` |
69
+ | 12 | 8 | - | US | any | `ADVANCED` |
70
+ | 13 | 6 | - | US | any | `ADVANCED` |
71
+ | 14 | 6 | - | CA | any | `ADVANCED` |
72
+ | 15 | 6 | - | SE | true | `SIMPLE` |
73
+ | 16 | 6 | - | SE | false | `COMMON` |
74
+ | 17 | 3 | - | US | true | `SIMPLE` |
75
+ | 18 | 3 | - | US | false | `COMMON` |
76
+ | 19 | null | 8 | US | any | `ADVANCED` |
77
+ | 20 | null | null | - | true | `SIMPLE` |
78
+ | 21 | null | null | - | false | `COMMON` |
79
+
80
+ **Advanced threshold:**
81
+
82
+ | Locale | Grade >= | Result |
83
+ |----------|----------|------------|
84
+ | US or CA | 6 | `ADVANCED` |
85
+ | Other | 7 | `ADVANCED` |
86
+
87
+ **Priority:** `ADVANCED` > `SIMPLE` > `COMMON`
88
+
89
+ ---
90
+
91
+ ## Step 4: `answerArea`
92
+
93
+ | # | isSimpleMode | practice.isEnabled | hasAnswerVariants | answerType | characterType | answerArea |
94
+ |----|--------------|--------------------|-------------------|--------------|---------------|------------|
95
+ | 22 | false | any | any | any | any | `REGULAR` |
96
+ | 23 | true | true | any | any | any | `SIMPLE` |
97
+ | 24 | true | false | true | any | any | `SIMPLE` |
98
+ | 25 | true | false | false | HANDWRITING | 10 | `SIMPLE` |
99
+ | 26 | true | false | false | HANDWRITING | 5 | `REGULAR` |
100
+ | 27 | true | false | false | MULTI_CHOICE | 10 | `REGULAR` |
101
+ | 28 | true | false | false | other | any | `REGULAR` |
102
+
103
+ ---
104
+
105
+ ## Full combined scenarios
106
+
107
+ | # | Mode | user.grade | assignment.grade | practice.grade | locale | hasVariants | answerType | charType | general | toolbar | answerArea |
108
+ |----|----------|------------|------------------|----------------|--------|-------------|-------------|----------|-----------|------------|------------|
109
+ | 29 | practice | - | - | 1 | US | true | - | - | `SIMPLE` | `SIMPLE` | `SIMPLE` |
110
+ | 30 | practice | - | - | 8 | US | false | - | - | `REGULAR` | `ADVANCED` | `REGULAR` |
111
+ | 31 | regular | 2 | 7 | - | SE | true | - | - | `SIMPLE` | `ADVANCED` | `SIMPLE` |
112
+ | 32 | regular | 5 | 3 | - | US | false | SINGLE | - | `REGULAR` | `COMMON` | `REGULAR` |
113
+ | 33 | regular | null | 1 | - | SE | false | HANDWRITING | 10 | `SIMPLE` | `SIMPLE` | `SIMPLE` |
114
+ | 34 | regular | null | null | null | SE | - | - | - | `REGULAR` | `COMMON` | `REGULAR` |
@@ -0,0 +1,364 @@
1
+ jest.mock('@magmamath/react-native-draw-board', () => ({
2
+ ToolBarVariants: {
3
+ COMMON: 'COMMON',
4
+ SIMPLE: 'SIMPLE',
5
+ ADVANCED: 'ADVANCED',
6
+ REPLAY: 'REPLAY',
7
+ NO_CONTROLLER: 'NO_CONTROLLER',
8
+ },
9
+ }))
10
+
11
+ jest.mock('@magmamath/frontend-config', () => ({
12
+ Locale: {
13
+ US: 'en-SE',
14
+ SE: 'sv-SE',
15
+ CA: 'en-CA',
16
+ GB: 'en-GB',
17
+ SCT: 'en-SCT',
18
+ DE: 'de-DE',
19
+ },
20
+ }))
21
+
22
+ import { getUIMode } from '../getUIMode'
23
+ import { UIMode } from '../uiMode.constants'
24
+ import { AnswerType } from '../../../types/answerTypes'
25
+ import { MyScriptMathCharacterTypes } from '../../../types/characterTypes'
26
+ import { ToolBarVariants } from '@magmamath/react-native-draw-board'
27
+ import { Locale } from '@magmamath/frontend-config'
28
+ import { GetUIModeProps } from '../uiMode.types'
29
+
30
+ const defaults: GetUIModeProps = {
31
+ user: { grade: null },
32
+ practice: { isEnabled: false, grade: null },
33
+ assignment: { grade: null },
34
+ locale: Locale.US,
35
+ problem: {
36
+ answerType: AnswerType.HANDWRITING,
37
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
38
+ hasAnswerVariants: false,
39
+ },
40
+ }
41
+
42
+ const getUIModeWithDefaults = (overrides: Partial<GetUIModeProps>) =>
43
+ getUIMode({ ...defaults, ...overrides })
44
+
45
+ describe('practice mode uses practice grade to determine simple mode (grades 0-2 are simple)', () => {
46
+ it('grade 0 → simple', () => {
47
+ const result = getUIModeWithDefaults({ practice: { isEnabled: true, grade: 0 } })
48
+ expect(result.general).toBe(UIMode.SIMPLE)
49
+ })
50
+
51
+ it('grade 2 → simple', () => {
52
+ const result = getUIModeWithDefaults({ practice: { isEnabled: true, grade: 2 } })
53
+ expect(result.general).toBe(UIMode.SIMPLE)
54
+ })
55
+
56
+ it('grade 3 → regular', () => {
57
+ const result = getUIModeWithDefaults({ practice: { isEnabled: true, grade: 3 } })
58
+ expect(result.general).toBe(UIMode.REGULAR)
59
+ })
60
+
61
+ it('null grade → regular', () => {
62
+ const result = getUIModeWithDefaults({ practice: { isEnabled: true, grade: null } })
63
+ expect(result.general).toBe(UIMode.REGULAR)
64
+ })
65
+
66
+ it('young student practicing with answer variants gets full simple experience', () => {
67
+ const result = getUIModeWithDefaults({
68
+ practice: { isEnabled: true, grade: 1 },
69
+ locale: Locale.US,
70
+ problem: {
71
+ answerType: AnswerType.HANDWRITING,
72
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
73
+ hasAnswerVariants: true,
74
+ },
75
+ })
76
+ expect(result).toEqual({
77
+ general: UIMode.SIMPLE,
78
+ toolbar: ToolBarVariants.SIMPLE,
79
+ answerArea: UIMode.SIMPLE,
80
+ })
81
+ })
82
+
83
+ it('older student practicing gets advanced toolbar with regular UI', () => {
84
+ const result = getUIModeWithDefaults({
85
+ practice: { isEnabled: true, grade: 8 },
86
+ locale: Locale.US,
87
+ problem: {
88
+ answerType: AnswerType.HANDWRITING,
89
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
90
+ hasAnswerVariants: false,
91
+ },
92
+ })
93
+ expect(result).toEqual({
94
+ general: UIMode.REGULAR,
95
+ toolbar: ToolBarVariants.ADVANCED,
96
+ answerArea: UIMode.REGULAR,
97
+ })
98
+ })
99
+ })
100
+
101
+ describe('regular mode uses user grade, falls back to assignment grade when user grade is null, undefined, or -1', () => {
102
+ it('user grade 1 → simple', () => {
103
+ const result = getUIModeWithDefaults({ user: { grade: 1 } })
104
+ expect(result.general).toBe(UIMode.SIMPLE)
105
+ })
106
+
107
+ it('user grade 5 → regular', () => {
108
+ const result = getUIModeWithDefaults({ user: { grade: 5 } })
109
+ expect(result.general).toBe(UIMode.REGULAR)
110
+ })
111
+
112
+ it('user grade null falls back to assignment grade 2 → simple', () => {
113
+ const result = getUIModeWithDefaults({ user: { grade: null }, assignment: { grade: 2 } })
114
+ expect(result.general).toBe(UIMode.SIMPLE)
115
+ })
116
+
117
+ it('user grade undefined falls back to assignment grade 2 → simple', () => {
118
+ const result = getUIModeWithDefaults({ user: { grade: undefined }, assignment: { grade: 2 } })
119
+ expect(result.general).toBe(UIMode.SIMPLE)
120
+ })
121
+
122
+ it('user grade -1 (invalid) falls back to assignment grade 2 → simple', () => {
123
+ const result = getUIModeWithDefaults({ user: { grade: -1 }, assignment: { grade: 2 } })
124
+ expect(result.general).toBe(UIMode.SIMPLE)
125
+ })
126
+
127
+ it('user grade null falls back to assignment grade 5 → regular', () => {
128
+ const result = getUIModeWithDefaults({ user: { grade: null }, assignment: { grade: 5 } })
129
+ expect(result.general).toBe(UIMode.REGULAR)
130
+ })
131
+
132
+ it('user grade undefined falls back to assignment grade 5 → regular', () => {
133
+ const result = getUIModeWithDefaults({ user: { grade: undefined }, assignment: { grade: 5 } })
134
+ expect(result.general).toBe(UIMode.REGULAR)
135
+ })
136
+
137
+ it('both user and assignment grade null → regular', () => {
138
+ const result = getUIModeWithDefaults({ user: { grade: null }, assignment: { grade: null } })
139
+ expect(result.general).toBe(UIMode.REGULAR)
140
+ })
141
+
142
+ it('user grade 2 in grade 7 SE assignment gets simple mode but advanced toolbar', () => {
143
+ const result = getUIModeWithDefaults({
144
+ user: { grade: 2 },
145
+ assignment: { grade: 7 },
146
+ locale: Locale.SE,
147
+ problem: {
148
+ answerType: AnswerType.HANDWRITING,
149
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
150
+ hasAnswerVariants: true,
151
+ },
152
+ })
153
+ expect(result).toEqual({
154
+ general: UIMode.SIMPLE,
155
+ toolbar: ToolBarVariants.ADVANCED,
156
+ answerArea: UIMode.SIMPLE,
157
+ })
158
+ })
159
+
160
+ it('user grade 5 in grade 3 US assignment gets fully regular experience', () => {
161
+ const result = getUIModeWithDefaults({
162
+ user: { grade: 5 },
163
+ assignment: { grade: 3 },
164
+ locale: Locale.US,
165
+ problem: {
166
+ answerType: AnswerType.SINGLE_CHOICE,
167
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
168
+ hasAnswerVariants: false,
169
+ },
170
+ })
171
+ expect(result).toEqual({
172
+ general: UIMode.REGULAR,
173
+ toolbar: ToolBarVariants.COMMON,
174
+ answerArea: UIMode.REGULAR,
175
+ })
176
+ })
177
+
178
+ it('unknown user falls back to assignment grade 1 in SE with handwriting whole numbers', () => {
179
+ const result = getUIModeWithDefaults({
180
+ user: { grade: null },
181
+ assignment: { grade: 1 },
182
+ locale: Locale.SE,
183
+ problem: {
184
+ answerType: AnswerType.HANDWRITING,
185
+ characterType: MyScriptMathCharacterTypes.NUMBERS_WHOLE,
186
+ hasAnswerVariants: false,
187
+ },
188
+ })
189
+ expect(result).toEqual({
190
+ general: UIMode.SIMPLE,
191
+ toolbar: ToolBarVariants.SIMPLE,
192
+ answerArea: UIMode.SIMPLE,
193
+ })
194
+ })
195
+
196
+ it('all grades unknown defaults to fully regular experience', () => {
197
+ const result = getUIModeWithDefaults({
198
+ user: { grade: null },
199
+ assignment: { grade: null },
200
+ practice: { isEnabled: false, grade: null },
201
+ locale: Locale.SE,
202
+ })
203
+ expect(result).toEqual({
204
+ general: UIMode.REGULAR,
205
+ toolbar: ToolBarVariants.COMMON,
206
+ answerArea: UIMode.REGULAR,
207
+ })
208
+ })
209
+ })
210
+
211
+ describe('toolbar is ADVANCED for high grades (>=6 US/CA, >=7 elsewhere), SIMPLE for young students, COMMON otherwise', () => {
212
+ it('grade 7 in SE → ADVANCED', () => {
213
+ const result = getUIModeWithDefaults({ assignment: { grade: 7 }, locale: Locale.SE, user: { grade: 7 } })
214
+ expect(result.toolbar).toBe(ToolBarVariants.ADVANCED)
215
+ })
216
+
217
+ it('grade 8 in US → ADVANCED', () => {
218
+ const result = getUIModeWithDefaults({ assignment: { grade: 8 }, locale: Locale.US, user: { grade: 8 } })
219
+ expect(result.toolbar).toBe(ToolBarVariants.ADVANCED)
220
+ })
221
+
222
+ it('grade 6 in US → ADVANCED', () => {
223
+ const result = getUIModeWithDefaults({ assignment: { grade: 6 }, locale: Locale.US, user: { grade: 6 } })
224
+ expect(result.toolbar).toBe(ToolBarVariants.ADVANCED)
225
+ })
226
+
227
+ it('grade 6 in CA → ADVANCED', () => {
228
+ const result = getUIModeWithDefaults({ assignment: { grade: 6 }, locale: Locale.CA, user: { grade: 6 } })
229
+ expect(result.toolbar).toBe(ToolBarVariants.ADVANCED)
230
+ })
231
+
232
+ it('grade 6 in SE with simple mode student → SIMPLE (not advanced in SE until grade 7)', () => {
233
+ const result = getUIModeWithDefaults({ assignment: { grade: 6 }, locale: Locale.SE, user: { grade: 1 } })
234
+ expect(result.toolbar).toBe(ToolBarVariants.SIMPLE)
235
+ })
236
+
237
+ it('grade 6 in SE with regular mode student → COMMON', () => {
238
+ const result = getUIModeWithDefaults({ assignment: { grade: 6 }, locale: Locale.SE, user: { grade: 6 } })
239
+ expect(result.toolbar).toBe(ToolBarVariants.COMMON)
240
+ })
241
+
242
+ it('grade 3 in US with simple mode student → SIMPLE', () => {
243
+ const result = getUIModeWithDefaults({ assignment: { grade: 3 }, locale: Locale.US, user: { grade: 1 } })
244
+ expect(result.toolbar).toBe(ToolBarVariants.SIMPLE)
245
+ })
246
+
247
+ it('grade 3 in US with regular mode student → COMMON', () => {
248
+ const result = getUIModeWithDefaults({ assignment: { grade: 3 }, locale: Locale.US, user: { grade: 3 } })
249
+ expect(result.toolbar).toBe(ToolBarVariants.COMMON)
250
+ })
251
+
252
+ it('no assignment grade falls back to practice grade 8 → ADVANCED', () => {
253
+ const result = getUIModeWithDefaults({
254
+ assignment: { grade: null },
255
+ practice: { isEnabled: true, grade: 8 },
256
+ locale: Locale.US,
257
+ })
258
+ expect(result.toolbar).toBe(ToolBarVariants.ADVANCED)
259
+ })
260
+
261
+ it('no grades at all with simple mode → SIMPLE', () => {
262
+ const result = getUIModeWithDefaults({
263
+ assignment: { grade: null },
264
+ practice: { isEnabled: true, grade: 1 },
265
+ })
266
+ expect(result.toolbar).toBe(ToolBarVariants.SIMPLE)
267
+ })
268
+
269
+ it('no grades at all with regular mode → COMMON', () => {
270
+ const result = getUIModeWithDefaults({
271
+ assignment: { grade: null },
272
+ practice: { isEnabled: false, grade: null },
273
+ user: { grade: 5 },
274
+ })
275
+ expect(result.toolbar).toBe(ToolBarVariants.COMMON)
276
+ })
277
+ })
278
+
279
+ describe('answer area is SIMPLE only in simple mode when practicing, has variants, or handwriting whole numbers', () => {
280
+ it('regular mode → always REGULAR regardless of other inputs', () => {
281
+ const result = getUIModeWithDefaults({
282
+ user: { grade: 5 },
283
+ practice: { isEnabled: true, grade: 5 },
284
+ problem: {
285
+ answerType: AnswerType.HANDWRITING,
286
+ characterType: MyScriptMathCharacterTypes.NUMBERS_WHOLE,
287
+ hasAnswerVariants: true,
288
+ },
289
+ })
290
+ expect(result.answerArea).toBe(UIMode.REGULAR)
291
+ })
292
+
293
+ it('simple mode + practice exercise → SIMPLE', () => {
294
+ const result = getUIModeWithDefaults({
295
+ practice: { isEnabled: true, grade: 1 },
296
+ problem: {
297
+ answerType: AnswerType.HANDWRITING,
298
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
299
+ hasAnswerVariants: false,
300
+ },
301
+ })
302
+ expect(result.answerArea).toBe(UIMode.SIMPLE)
303
+ })
304
+
305
+ it('simple mode + answer variants → SIMPLE', () => {
306
+ const result = getUIModeWithDefaults({
307
+ user: { grade: 1 },
308
+ problem: {
309
+ answerType: AnswerType.HANDWRITING,
310
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
311
+ hasAnswerVariants: true,
312
+ },
313
+ })
314
+ expect(result.answerArea).toBe(UIMode.SIMPLE)
315
+ })
316
+
317
+ it('simple mode + handwriting whole numbers → SIMPLE', () => {
318
+ const result = getUIModeWithDefaults({
319
+ user: { grade: 1 },
320
+ problem: {
321
+ answerType: AnswerType.HANDWRITING,
322
+ characterType: MyScriptMathCharacterTypes.NUMBERS_WHOLE,
323
+ hasAnswerVariants: false,
324
+ },
325
+ })
326
+ expect(result.answerArea).toBe(UIMode.SIMPLE)
327
+ })
328
+
329
+ it('simple mode + handwriting but not whole numbers → REGULAR', () => {
330
+ const result = getUIModeWithDefaults({
331
+ user: { grade: 1 },
332
+ problem: {
333
+ answerType: AnswerType.HANDWRITING,
334
+ characterType: MyScriptMathCharacterTypes.NUMBERS,
335
+ hasAnswerVariants: false,
336
+ },
337
+ })
338
+ expect(result.answerArea).toBe(UIMode.REGULAR)
339
+ })
340
+
341
+ it('simple mode + multiple choice even with whole numbers → REGULAR', () => {
342
+ const result = getUIModeWithDefaults({
343
+ user: { grade: 1 },
344
+ problem: {
345
+ answerType: AnswerType.MULTIPLE_CHOICE,
346
+ characterType: MyScriptMathCharacterTypes.NUMBERS_WHOLE,
347
+ hasAnswerVariants: false,
348
+ },
349
+ })
350
+ expect(result.answerArea).toBe(UIMode.REGULAR)
351
+ })
352
+
353
+ it('simple mode + no special conditions → REGULAR', () => {
354
+ const result = getUIModeWithDefaults({
355
+ user: { grade: 1 },
356
+ problem: {
357
+ answerType: AnswerType.SINGLE_CHOICE,
358
+ characterType: MyScriptMathCharacterTypes.DEFAULT,
359
+ hasAnswerVariants: false,
360
+ },
361
+ })
362
+ expect(result.answerArea).toBe(UIMode.REGULAR)
363
+ })
364
+ })
@@ -0,0 +1,28 @@
1
+ import { GetUIModeProps, UIModeResult } from './uiMode.types'
2
+ import { getAnswerAreaMode, getToolbarMode, isSimpleMode } from './uiMode.helpers'
3
+ import { UIMode } from './uiMode.constants'
4
+
5
+ export const getUIMode = ({
6
+ user,
7
+ practice,
8
+ assignment,
9
+ locale,
10
+ problem,
11
+ }: GetUIModeProps): UIModeResult => {
12
+ const grade = assignment.grade ?? practice.grade
13
+ const isSimple = isSimpleMode({ user, practice, assignment })
14
+
15
+ if (!isSimple) {
16
+ return {
17
+ general: UIMode.REGULAR,
18
+ toolbar: getToolbarMode({ isSimpleModeGrade: false, grade, locale }),
19
+ answerArea: UIMode.REGULAR,
20
+ }
21
+ }
22
+
23
+ return {
24
+ general: UIMode.SIMPLE,
25
+ toolbar: getToolbarMode({ isSimpleModeGrade: true, grade, locale }),
26
+ answerArea: getAnswerAreaMode({ practice, problem }),
27
+ }
28
+ }
@@ -0,0 +1,2 @@
1
+ export { UIMode } from './uiMode.constants'
2
+ export { getUIMode } from './getUIMode'
@@ -0,0 +1,7 @@
1
+ export const GRADE_K2 = 2
2
+ export const INVALID_GRADE = -1
3
+
4
+ export enum UIMode {
5
+ REGULAR = 'REGULAR',
6
+ SIMPLE = 'SIMPLE',
7
+ }
@@ -0,0 +1,52 @@
1
+ import { UIMode, GRADE_K2, INVALID_GRADE } from './uiMode.constants'
2
+ import {
3
+ GetAnswerAreaModeProps,
4
+ GetToolbarModeProps,
5
+ Grade,
6
+ IsSimpleModeProps,
7
+ } from './uiMode.types'
8
+
9
+ import { AnswerType } from '../../types/answerTypes'
10
+ import { MyScriptMathCharacterTypes } from '../../types/characterTypes'
11
+ import { ToolBarVariants } from '@magmamath/react-native-draw-board'
12
+ import { Locale } from '@magmamath/frontend-config'
13
+
14
+ const isValidGrade = (grade: Grade): grade is number => {
15
+ return grade !== undefined && grade !== null && grade !== INVALID_GRADE
16
+ }
17
+
18
+ export const isBelowGradeK2 = (grade: Grade) => {
19
+ return isValidGrade(grade) && grade >= 0 && grade <= GRADE_K2
20
+ }
21
+
22
+ export const isSimpleMode = ({ user, practice, assignment }: IsSimpleModeProps) => {
23
+ if (practice.isEnabled) return isBelowGradeK2(practice.grade)
24
+ if (!isValidGrade(user.grade)) return isBelowGradeK2(assignment.grade)
25
+ return isBelowGradeK2(user.grade)
26
+ }
27
+
28
+ export const getAnswerAreaMode = ({ practice, problem }: GetAnswerAreaModeProps): UIMode => {
29
+ const isHandwritingNumbersWhole =
30
+ problem.answerType === AnswerType.HANDWRITING &&
31
+ problem.characterType === MyScriptMathCharacterTypes.NUMBERS_WHOLE
32
+
33
+ if (practice.isEnabled || problem.hasAnswerVariants || isHandwritingNumbersWhole) {
34
+ return UIMode.SIMPLE
35
+ }
36
+
37
+ return UIMode.REGULAR
38
+ }
39
+
40
+ export const getToolbarMode = ({
41
+ isSimpleModeGrade,
42
+ grade,
43
+ locale,
44
+ }: GetToolbarModeProps): ToolBarVariants => {
45
+ const isUSOrCA = locale === Locale.US || locale === Locale.CA
46
+ const gradeThreshold = isUSOrCA ? 6 : 7
47
+ const isAdvanced = isValidGrade(grade) && grade >= gradeThreshold
48
+
49
+ if (isAdvanced) return ToolBarVariants.ADVANCED
50
+ if (isSimpleModeGrade) return ToolBarVariants.SIMPLE
51
+ return ToolBarVariants.COMMON
52
+ }
@@ -0,0 +1,46 @@
1
+ import { Locale } from '@magmamath/frontend-config'
2
+ import { AnswerType } from '../../types/answerTypes'
3
+ import { MyScriptMathCharacterTypes } from '../../types/characterTypes'
4
+ import { UIMode } from './uiMode.constants'
5
+ import { ToolBarVariants } from '@magmamath/react-native-draw-board'
6
+
7
+ export type Grade = number | null | undefined
8
+
9
+ export type GetUIModeProps = {
10
+ locale: Locale
11
+ user: { grade: Grade }
12
+ practice: { isEnabled: boolean; grade: Grade }
13
+ assignment: { grade: Grade }
14
+ problem: {
15
+ answerType: AnswerType
16
+ characterType: MyScriptMathCharacterTypes
17
+ hasAnswerVariants: boolean
18
+ }
19
+ }
20
+
21
+ export type UIModeResult = {
22
+ general: UIMode
23
+ toolbar: ToolBarVariants
24
+ answerArea: UIMode
25
+ }
26
+
27
+ export type IsSimpleModeProps = {
28
+ user: { grade: Grade }
29
+ practice: { isEnabled: boolean; grade: Grade }
30
+ assignment: { grade: Grade }
31
+ }
32
+
33
+ export type GetAnswerAreaModeProps = {
34
+ practice: { isEnabled: boolean }
35
+ problem: {
36
+ answerType: AnswerType
37
+ characterType: MyScriptMathCharacterTypes
38
+ hasAnswerVariants: boolean
39
+ }
40
+ }
41
+
42
+ export type GetToolbarModeProps = {
43
+ isSimpleModeGrade: boolean
44
+ grade: Grade
45
+ locale: Locale
46
+ }
package/src/index.ts CHANGED
@@ -13,3 +13,4 @@ export * from './features/pmProgress'
13
13
  export * from './features/openEnded'
14
14
  export * from './shared/icons'
15
15
  export * from './features/voice'
16
+ export * from './features/uiMode'
@@ -1,33 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "InterfaceMode", {
7
- enumerable: true,
8
- get: function () {
9
- return _interfaceModeConstants.InterfaceMode;
10
- }
11
- });
12
- Object.defineProperty(exports, "InterfaceModeModel", {
13
- enumerable: true,
14
- get: function () {
15
- return _InterfaceModeModel.InterfaceModeModel;
16
- }
17
- });
18
- Object.defineProperty(exports, "MAX_SIMPLE_MODE_GRADE", {
19
- enumerable: true,
20
- get: function () {
21
- return _interfaceModeConstants.MAX_SIMPLE_MODE_GRADE;
22
- }
23
- });
24
- Object.defineProperty(exports, "isSimpleGrade", {
25
- enumerable: true,
26
- get: function () {
27
- return _interfaceModeHelpers.isSimpleGrade;
28
- }
29
- });
30
- var _interfaceModeHelpers = require("./interfaceMode.helpers.js");
31
- var _interfaceModeConstants = require("./interfaceMode.constants.js");
32
- var _InterfaceModeModel = require("./model/InterfaceModeModel.js");
33
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_interfaceModeHelpers","require","_interfaceModeConstants","_InterfaceModeModel"],"sourceRoot":"../../../../src","sources":["features/interfaceMode/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,qBAAA,GAAAC,OAAA;AACA,IAAAC,uBAAA,GAAAD,OAAA;AACA,IAAAE,mBAAA,GAAAF,OAAA","ignoreList":[]}