@magmamath/students-features 1.2.1-rc.31 → 1.2.1-rc.32

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.
@@ -8,6 +8,7 @@ var _effector = require("effector");
8
8
  var _effectorAction = require("effector-action");
9
9
  var _skillsUtils = require("@matteappen/skills-utils");
10
10
  var _pmProgressHelpers = require("../shared/pmProgress.helpers.js");
11
+ var _TreeNormalizer = require("../shared/TreeNormalizer.js");
11
12
  var _session = require("effector-storage/session");
12
13
  var _pmProgressConstants = require("../shared/pmProgress.constants.js");
13
14
  class PmTreeModel {
@@ -98,12 +99,13 @@ class PmTreeModel {
98
99
  target: this.setDomains
99
100
  });
100
101
  }
101
- initTreeFx = (0, _effector.createEffect)(({
102
+ initTreeFx = (0, _effector.createEffect)(async ({
102
103
  user
103
104
  }) => {
104
- return Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
105
+ const [tree, stats] = await Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
105
106
  entityIds: [user._id]
106
107
  })]);
108
+ return [_TreeNormalizer.TreeNormalizer.normalize(tree), stats];
107
109
  });
108
110
  getTreeContextFx = (0, _effector.attach)({
109
111
  source: {
@@ -1 +1 @@
1
- {"version":3,"names":["_effector","require","_effectorAction","_skillsUtils","_pmProgressHelpers","_session","_pmProgressConstants","PmTreeModel","$tree","createStore","$stats","$user","setupInitialGrade","createEvent","setDomains","setGrade","$isInitialized","$grade","restore","$domains","$grades","constructor","api","persist","key","SessionStorageKeys","GRADE","store","DOMAINS","createAction","initTreeFx","done","target","fn","params","user","result","tree","stats","getTreeGrades","sample","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","getInitialPmGrade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","isTreeDataReady","treeWithUserStats","enhanceProgressMatrixData","entityId","_id","name","fullName","getDomainStructure","createEffect","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","getTreeContextFx","attach","mapParams","_","Error","effect","treeWithStats","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_effector","require","_effectorAction","_skillsUtils","_pmProgressHelpers","_TreeNormalizer","_session","_pmProgressConstants","PmTreeModel","$tree","createStore","$stats","$user","setupInitialGrade","createEvent","setDomains","setGrade","$isInitialized","$grade","restore","$domains","$grades","constructor","api","persist","key","SessionStorageKeys","GRADE","store","DOMAINS","createAction","initTreeFx","done","target","fn","params","user","result","tree","stats","getTreeGrades","sample","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","getInitialPmGrade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","isTreeDataReady","treeWithUserStats","enhanceProgressMatrixData","entityId","_id","name","fullName","getDomainStructure","createEffect","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","TreeNormalizer","normalize","getTreeContextFx","attach","mapParams","_","Error","effect","treeWithStats","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAaA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAH,OAAA;AAMA,IAAAI,eAAA,GAAAJ,OAAA;AACA,IAAAK,QAAA,GAAAL,OAAA;AACA,IAAAM,oBAAA,GAAAN,OAAA;AAEO,MAAMO,WAAW,CAAC;EACNC,KAAK,GAAG,IAAAC,qBAAW,EAA6B,IAAI,CAAC;EACrDC,MAAM,GAAG,IAAAD,qBAAW,EAAuB,IAAI,CAAC;EAChDE,KAAK,GAAG,IAAAF,qBAAW,EAAc,IAAI,CAAC;EAEtCG,iBAAiB,GAAG,IAAAC,qBAAW,EAAyB,CAAC;EACzDC,UAAU,GAAG,IAAAD,qBAAW,EAAW,CAAC;EACrCE,QAAQ,GAAG,IAAAF,qBAAW,EAAgB,CAAC;EAEvCG,cAAc,GAAG,IAAAP,qBAAW,EAAC,KAAK,CAAC;EACnCQ,MAAM,GAAG,IAAAC,iBAAO,EAAC,IAAI,CAACH,QAAQ,EAAE,IAAI,CAAC;EACrCI,QAAQ,GAAG,IAAAD,iBAAO,EAAC,IAAI,CAACJ,UAAU,EAAE,EAAE,CAAC;EACvCM,OAAO,GAAG,IAAAX,qBAAW,EAAU,EAAE,CAAC;EAElDY,WAAWA,CAAkBC,GAAkB,EAAE;IAAA,KAApBA,GAAkB,GAAlBA,GAAkB;IAC7C,IAAAC,gBAAO,EAAC;MAAEC,GAAG,EAAEC,uCAAkB,CAACC,KAAK;MAAEC,KAAK,EAAE,IAAI,CAACV;IAAO,CAAC,CAAC;IAC9D,IAAAM,gBAAO,EAAC;MAAEC,GAAG,EAAEC,uCAAkB,CAACG,OAAO;MAAED,KAAK,EAAE,IAAI,CAACR;IAAS,CAAC,CAAC;IAElE,IAAAU,4BAAY,EAAC,IAAI,CAACC,UAAU,CAACC,IAAI,EAAE;MACjCC,MAAM,EAAE;QACNxB,KAAK,EAAE,IAAI,CAACA,KAAK;QACjBE,MAAM,EAAE,IAAI,CAACA,MAAM;QACnBC,KAAK,EAAE,IAAI,CAACA,KAAK;QACjBS,OAAO,EAAE,IAAI,CAACA,OAAO;QACrBJ,cAAc,EAAE,IAAI,CAACA,cAAc;QACnCJ,iBAAiB,EAAE,IAAI,CAACA;MAC1B,CAAC;MACDqB,EAAE,EAAEA,CAACD,MAAM,EAAE;QAAEE,MAAM,EAAE;UAAEC;QAAK,CAAC;QAAEC,MAAM,EAAE,CAACC,IAAI,EAAEC,KAAK;MAAE,CAAC,KAAK;QAC3DN,MAAM,CAACxB,KAAK,CAAC6B,IAAI,CAAC;QAClBL,MAAM,CAACtB,MAAM,CAAC4B,KAAK,CAAC;QACpBN,MAAM,CAACrB,KAAK,CAACwB,IAAI,CAAC;QAClBH,MAAM,CAACZ,OAAO,CAAC,IAAAmB,gCAAa,EAACF,IAAI,EAAEF,IAAI,CAAC,CAAC;QACzCH,MAAM,CAACpB,iBAAiB,CAAC;UAAEyB,IAAI;UAAEF;QAAK,CAAC,CAAC;QACxCH,MAAM,CAAChB,cAAc,CAAC,IAAI,CAAC;MAC7B;IACF,CAAC,CAAC;IAEF,IAAAwB,gBAAM,EAAC;MACLC,KAAK,EAAE,IAAI,CAAC7B,iBAAiB;MAC7B8B,MAAM,EAAEA,CAAA,KAAMC,cAAc,CAACC,OAAO,CAACnB,uCAAkB,CAACC,KAAK,CAAC,KAAK,IAAI;MACvEO,EAAE,EAAEA,CAAC;QAAEI,IAAI;QAAEF;MAAK,CAAC,KAAK;QACtB,MAAMU,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,CAC/CN,MAAM,CAAEO,IAAI,IAAKA,IAAI,CAACC,IAAI,KAAK,OAAO,CAAC,CACvCC,GAAG,CAAEF,IAAI,IAAKA,IAAI,CAACG,UAAU,CAACC,KAAK,CAAC;QAEvC,OAAO,IAAAC,oCAAiB,EAAC;UACvBC,SAAS,EAAEpB,IAAI,CAACkB,KAAK;UACrBR,UAAU;UACVW,YAAY,EAAErB,IAAI,CAACsB,OAAO,CAACC,wBAAwB;UACnDC,cAAc,EAAExB,IAAI,CAACwB;QACvB,CAAC,CAAC;MACJ,CAAC;MACD3B,MAAM,EAAE,IAAI,CAACjB;IACf,CAAC,CAAC;IAEF,IAAAyB,gBAAM,EAAC;MACLC,KAAK,EAAE,CAAC,IAAI,CAACxB,MAAM,EAAE,IAAI,CAACa,UAAU,CAAC8B,QAAQ,CAAC;MAC9CC,MAAM,EAAE;QAAExB,IAAI,EAAE,IAAI,CAAC7B,KAAK;QAAE8B,KAAK,EAAE,IAAI,CAAC5B,MAAM;QAAEyB,IAAI,EAAE,IAAI,CAACxB,KAAK;QAAE0C,KAAK,EAAE,IAAI,CAACpC;MAAO,CAAC;MACtFyB,MAAM,EAAEoB,kCAAe;MACvB7B,EAAE,EAAEA,CAAC;QAAEI,IAAI;QAAEC,KAAK;QAAEH,IAAI;QAAEkB;MAAM,CAAC,KAAK;QACpC,MAAM,CAACU,iBAAiB,CAAC,GAAG,IAAAC,sCAAyB,EACnDlB,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,EAC/BV,KAAK,EACL,CAAC;UAAE2B,QAAQ,EAAE9B,IAAI,CAAC+B,GAAG;UAAEC,IAAI,EAAEhC,IAAI,CAACiC;QAAS,CAAC,CAAC,EAC7Cf,KACF,CAAC;QAED,OAAO,IAAAgB,qCAAkB,EAACN,iBAAiB,EAAE1B,IAAI,CAACW,WAAW,CAAC;MAChE,CAAC;MACDhB,MAAM,EAAE,IAAI,CAAClB;IACf,CAAC,CAAC;EACJ;EAEOgB,UAAU,GAAG,IAAAwC,sBAAY,EAAC,OAAO;IAAEnC;EAA0B,CAAC,KAAK;IACxE,MAAM,CAACE,IAAI,EAAEC,KAAK,CAAC,GAAG,MAAMiC,OAAO,CAACC,GAAG,CAAC,CACtC,IAAI,CAAClD,GAAG,CAACmD,SAAS,CAACtC,IAAI,CAACsB,OAAO,CAACiB,kBAAkB,CAAC,EACnD,IAAI,CAACpD,GAAG,CAACqD,eAAe,CAAC;MAAEC,SAAS,EAAE,CAACzC,IAAI,CAAC+B,GAAG;IAAE,CAAC,CAAC,CACpD,CAAC;IACF,OAAO,CAACW,8BAAc,CAACC,SAAS,CAACzC,IAAI,CAAC,EAAEC,KAAK,CAAC;EAChD,CAAC,CAAC;EAEcyC,gBAAgB,GAAG,IAAAC,gBAAM,EAAC;IACxCnB,MAAM,EAAE;MAAExB,IAAI,EAAE,IAAI,CAAC7B,KAAK;MAAE8B,KAAK,EAAE,IAAI,CAAC5B,MAAM;MAAEyB,IAAI,EAAE,IAAI,CAACxB,KAAK;MAAE0C,KAAK,EAAE,IAAI,CAACpC;IAAO,CAAC;IACtFgE,SAAS,EAAEA,CAACC,CAAO,EAAErB,MAAM,KAA6B;MACtD,IAAI,CAAC,IAAAC,kCAAe,EAACD,MAAM,CAAC,EAAE;QAC5B,MAAM,IAAIsB,KAAK,CACb,iFACF,CAAC;MACH;MACA,OAAOtB,MAAM;IACf,CAAC;IACDuB,MAAM,EAAE,IAAAd,sBAAY,EAAC,CAAC;MAAEjC,IAAI;MAAEC,KAAK;MAAEH,IAAI;MAAEkB;IAA8B,CAAC,KAAkB;MAC1F,MAAM,CAACgC,aAAa,CAAC,GAAG,IAAArB,sCAAyB,EAC/ClB,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,EAC/BV,KAAK,EACL,CAAC;QAAE2B,QAAQ,EAAE9B,IAAI,CAAC+B,GAAG;QAAEC,IAAI,EAAEhC,IAAI,CAACiC;MAAS,CAAC,CAAC,EAC7Cf,KACF,CAAC;MACD,OAAO;QACLhB,IAAI;QACJC,KAAK;QACLH,IAAI;QACJkD;MACF,CAAC;IACH,CAAC;EACH,CAAC,CAAC;AACJ;AAACC,OAAA,CAAA/E,WAAA,GAAAA,WAAA","ignoreList":[]}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TreeNormalizer = void 0;
7
+ /**
8
+ * Some skills from the API lack a valid ability (missing sectionId and functionName),
9
+ * making them impossible to open in the solving flow. This normalizer strips those skills
10
+ * and cascades the cleanup - removing standards, domains, etc. that end up empty.
11
+ *
12
+ * Acts as a single place to sanitize the tree API response before it enters the app.
13
+ * Can be extended with additional normalizations as new edge cases arise.
14
+ */
15
+ class TreeNormalizer {
16
+ static normalize(response) {
17
+ const skillsMapping = this.getOnlyValidSkills(response.skillsMapping);
18
+ const validIds = new Set(Object.keys(skillsMapping));
19
+ const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds);
20
+ return {
21
+ ...response,
22
+ skillsMapping,
23
+ treeMapping
24
+ };
25
+ }
26
+ static isSkillValid(skill) {
27
+ return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName));
28
+ }
29
+ static getOnlyValidSkills(mapping) {
30
+ return Object.fromEntries(Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)));
31
+ }
32
+ static removeEmptyNodes(treeMapping, validIds) {
33
+ const emptyIds = this.getEmptyNodeIds(treeMapping, validIds);
34
+ return Object.fromEntries(Object.entries(treeMapping).filter(([id]) => !emptyIds.has(id)).map(([id, node]) => [id, {
35
+ ...node,
36
+ skills: node.skills.filter(sid => validIds.has(sid)),
37
+ children: node.children.filter(cid => !emptyIds.has(cid))
38
+ }]));
39
+ }
40
+ static getEmptyNodeIds(treeMapping, validIds) {
41
+ const empty = new Set();
42
+ const leafToRoot = Object.entries(treeMapping).sort(([, a], [, b]) => b.parents.length - a.parents.length);
43
+ for (const [id, node] of leafToRoot) {
44
+ const isEmptyLeaf = node.skills.length > 0 && node.skills.every(s => !validIds.has(s));
45
+ const isEmptyParent = node.children.length > 0 && node.children.every(c => empty.has(c));
46
+ if (isEmptyLeaf || isEmptyParent) empty.add(id);
47
+ }
48
+ return empty;
49
+ }
50
+ }
51
+ exports.TreeNormalizer = TreeNormalizer;
52
+ //# sourceMappingURL=TreeNormalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TreeNormalizer","normalize","response","skillsMapping","getOnlyValidSkills","validIds","Set","Object","keys","treeMapping","removeEmptyNodes","isSkillValid","skill","Boolean","ability","sectionId","functionName","mapping","fromEntries","entries","filter","emptyIds","getEmptyNodeIds","id","has","map","node","skills","sid","children","cid","empty","leafToRoot","sort","a","b","parents","length","isEmptyLeaf","every","s","isEmptyParent","c","add","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/shared/TreeNormalizer.ts"],"mappings":"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","ignoreList":[]}
@@ -4,6 +4,7 @@ import { attach, createEffect, createEvent, createStore, restore, sample } from
4
4
  import { createAction } from 'effector-action';
5
5
  import { enhanceProgressMatrixData } from '@matteappen/skills-utils';
6
6
  import { getDomainStructure, getInitialPmGrade, getTreeGrades, isTreeDataReady } from "../shared/pmProgress.helpers.js";
7
+ import { TreeNormalizer } from "../shared/TreeNormalizer.js";
7
8
  import { persist } from 'effector-storage/session';
8
9
  import { SessionStorageKeys } from "../shared/pmProgress.constants.js";
9
10
  export class PmTreeModel {
@@ -94,12 +95,13 @@ export class PmTreeModel {
94
95
  target: this.setDomains
95
96
  });
96
97
  }
97
- initTreeFx = createEffect(({
98
+ initTreeFx = createEffect(async ({
98
99
  user
99
100
  }) => {
100
- return Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
101
+ const [tree, stats] = await Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
101
102
  entityIds: [user._id]
102
103
  })]);
104
+ return [TreeNormalizer.normalize(tree), stats];
103
105
  });
104
106
  getTreeContextFx = attach({
105
107
  source: {
@@ -1 +1 @@
1
- {"version":3,"names":["attach","createEffect","createEvent","createStore","restore","sample","createAction","enhanceProgressMatrixData","getDomainStructure","getInitialPmGrade","getTreeGrades","isTreeDataReady","persist","SessionStorageKeys","PmTreeModel","$tree","$stats","$user","setupInitialGrade","setDomains","setGrade","$isInitialized","$grade","$domains","$grades","constructor","api","key","GRADE","store","DOMAINS","initTreeFx","done","target","fn","params","user","result","tree","stats","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","treeWithUserStats","entityId","_id","name","fullName","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","getTreeContextFx","mapParams","_","Error","effect","treeWithStats"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["attach","createEffect","createEvent","createStore","restore","sample","createAction","enhanceProgressMatrixData","getDomainStructure","getInitialPmGrade","getTreeGrades","isTreeDataReady","TreeNormalizer","persist","SessionStorageKeys","PmTreeModel","$tree","$stats","$user","setupInitialGrade","setDomains","setGrade","$isInitialized","$grade","$domains","$grades","constructor","api","key","GRADE","store","DOMAINS","initTreeFx","done","target","fn","params","user","result","tree","stats","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","treeWithUserStats","entityId","_id","name","fullName","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","normalize","getTreeContextFx","mapParams","_","Error","effect","treeWithStats"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Some skills from the API lack a valid ability (missing sectionId and functionName),
5
+ * making them impossible to open in the solving flow. This normalizer strips those skills
6
+ * and cascades the cleanup - removing standards, domains, etc. that end up empty.
7
+ *
8
+ * Acts as a single place to sanitize the tree API response before it enters the app.
9
+ * Can be extended with additional normalizations as new edge cases arise.
10
+ */
11
+ export class TreeNormalizer {
12
+ static normalize(response) {
13
+ const skillsMapping = this.getOnlyValidSkills(response.skillsMapping);
14
+ const validIds = new Set(Object.keys(skillsMapping));
15
+ const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds);
16
+ return {
17
+ ...response,
18
+ skillsMapping,
19
+ treeMapping
20
+ };
21
+ }
22
+ static isSkillValid(skill) {
23
+ return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName));
24
+ }
25
+ static getOnlyValidSkills(mapping) {
26
+ return Object.fromEntries(Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)));
27
+ }
28
+ static removeEmptyNodes(treeMapping, validIds) {
29
+ const emptyIds = this.getEmptyNodeIds(treeMapping, validIds);
30
+ return Object.fromEntries(Object.entries(treeMapping).filter(([id]) => !emptyIds.has(id)).map(([id, node]) => [id, {
31
+ ...node,
32
+ skills: node.skills.filter(sid => validIds.has(sid)),
33
+ children: node.children.filter(cid => !emptyIds.has(cid))
34
+ }]));
35
+ }
36
+ static getEmptyNodeIds(treeMapping, validIds) {
37
+ const empty = new Set();
38
+ const leafToRoot = Object.entries(treeMapping).sort(([, a], [, b]) => b.parents.length - a.parents.length);
39
+ for (const [id, node] of leafToRoot) {
40
+ const isEmptyLeaf = node.skills.length > 0 && node.skills.every(s => !validIds.has(s));
41
+ const isEmptyParent = node.children.length > 0 && node.children.every(c => empty.has(c));
42
+ if (isEmptyLeaf || isEmptyParent) empty.add(id);
43
+ }
44
+ return empty;
45
+ }
46
+ }
47
+ //# sourceMappingURL=TreeNormalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TreeNormalizer","normalize","response","skillsMapping","getOnlyValidSkills","validIds","Set","Object","keys","treeMapping","removeEmptyNodes","isSkillValid","skill","Boolean","ability","sectionId","functionName","mapping","fromEntries","entries","filter","emptyIds","getEmptyNodeIds","id","has","map","node","skills","sid","children","cid","empty","leafToRoot","sort","a","b","parents","length","isEmptyLeaf","every","s","isEmptyParent","c","add"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/shared/TreeNormalizer.ts"],"mappings":"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","ignoreList":[]}
@@ -13,7 +13,7 @@ export declare class PmTreeModel {
13
13
  readonly $domains: import("effector").StoreWritable<Domain[]>;
14
14
  readonly $grades: import("effector").StoreWritable<Grade[]>;
15
15
  constructor(api: PmProgressApi);
16
- initTreeFx: import("effector").Effect<PmProgressGateProps, [TreeMappingResponse, StatsResponse], Error>;
16
+ initTreeFx: import("effector").Effect<PmProgressGateProps, readonly [TreeMappingResponse, StatsResponse], Error>;
17
17
  readonly getTreeContextFx: import("effector").Effect<void, TreeContext, Error>;
18
18
  }
19
19
  //# sourceMappingURL=PmTreeModel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAW/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,8FAKf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
1
+ {"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAY/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,uGAMf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
@@ -0,0 +1,17 @@
1
+ import type { Skill, TreeMappingResponse } from './pmProgress.types';
2
+ /**
3
+ * Some skills from the API lack a valid ability (missing sectionId and functionName),
4
+ * making them impossible to open in the solving flow. This normalizer strips those skills
5
+ * and cascades the cleanup - removing standards, domains, etc. that end up empty.
6
+ *
7
+ * Acts as a single place to sanitize the tree API response before it enters the app.
8
+ * Can be extended with additional normalizations as new edge cases arise.
9
+ */
10
+ export declare class TreeNormalizer {
11
+ static normalize(response: TreeMappingResponse): TreeMappingResponse;
12
+ static isSkillValid(skill: Skill): boolean;
13
+ private static getOnlyValidSkills;
14
+ private static removeEmptyNodes;
15
+ private static getEmptyNodeIds;
16
+ }
17
+ //# sourceMappingURL=TreeNormalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeNormalizer.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/shared/TreeNormalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAInF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,mBAAmB;IAOpE,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK;IAIhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAMjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,eAAe;CAgB/B"}
@@ -13,7 +13,7 @@ export declare class PmTreeModel {
13
13
  readonly $domains: import("effector").StoreWritable<Domain[]>;
14
14
  readonly $grades: import("effector").StoreWritable<Grade[]>;
15
15
  constructor(api: PmProgressApi);
16
- initTreeFx: import("effector").Effect<PmProgressGateProps, [TreeMappingResponse, StatsResponse], Error>;
16
+ initTreeFx: import("effector").Effect<PmProgressGateProps, readonly [TreeMappingResponse, StatsResponse], Error>;
17
17
  readonly getTreeContextFx: import("effector").Effect<void, TreeContext, Error>;
18
18
  }
19
19
  //# sourceMappingURL=PmTreeModel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAW/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,8FAKf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
1
+ {"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAY/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,uGAMf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
@@ -0,0 +1,17 @@
1
+ import type { Skill, TreeMappingResponse } from './pmProgress.types';
2
+ /**
3
+ * Some skills from the API lack a valid ability (missing sectionId and functionName),
4
+ * making them impossible to open in the solving flow. This normalizer strips those skills
5
+ * and cascades the cleanup - removing standards, domains, etc. that end up empty.
6
+ *
7
+ * Acts as a single place to sanitize the tree API response before it enters the app.
8
+ * Can be extended with additional normalizations as new edge cases arise.
9
+ */
10
+ export declare class TreeNormalizer {
11
+ static normalize(response: TreeMappingResponse): TreeMappingResponse;
12
+ static isSkillValid(skill: Skill): boolean;
13
+ private static getOnlyValidSkills;
14
+ private static removeEmptyNodes;
15
+ private static getEmptyNodeIds;
16
+ }
17
+ //# sourceMappingURL=TreeNormalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeNormalizer.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/shared/TreeNormalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAInF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,mBAAmB;IAOpE,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK;IAIhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAMjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,eAAe;CAgB/B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magmamath/students-features",
3
- "version": "1.2.1-rc.31",
3
+ "version": "1.2.1-rc.32",
4
4
  "description": "Magmamath features library",
5
5
  "source": "src/index.ts",
6
6
  "main": "src/index.ts",
@@ -19,6 +19,7 @@ import {
19
19
  getTreeGrades,
20
20
  isTreeDataReady,
21
21
  } from '../shared/pmProgress.helpers'
22
+ import { TreeNormalizer } from '../shared/TreeNormalizer'
22
23
  import { persist } from 'effector-storage/session'
23
24
  import { SessionStorageKeys } from '../shared/pmProgress.constants'
24
25
 
@@ -95,11 +96,12 @@ export class PmTreeModel {
95
96
  })
96
97
  }
97
98
 
98
- public initTreeFx = createEffect(({ user }: PmProgressGateProps) => {
99
- return Promise.all([
99
+ public initTreeFx = createEffect(async ({ user }: PmProgressGateProps) => {
100
+ const [tree, stats] = await Promise.all([
100
101
  this.api.getTreeFx(user.setting.practiceModeTreeId),
101
102
  this.api.getStatisticsFx({ entityIds: [user._id] }),
102
103
  ])
104
+ return [TreeNormalizer.normalize(tree), stats] as const
103
105
  })
104
106
 
105
107
  public readonly getTreeContextFx = attach({
@@ -0,0 +1,64 @@
1
+ import type { Skill, SkillsMapping, TreeMappingResponse } from './pmProgress.types'
2
+
3
+ type TreeMapping = TreeMappingResponse['treeMapping']
4
+
5
+ /**
6
+ * Some skills from the API lack a valid ability (missing sectionId and functionName),
7
+ * making them impossible to open in the solving flow. This normalizer strips those skills
8
+ * and cascades the cleanup - removing standards, domains, etc. that end up empty.
9
+ *
10
+ * Acts as a single place to sanitize the tree API response before it enters the app.
11
+ * Can be extended with additional normalizations as new edge cases arise.
12
+ */
13
+ export class TreeNormalizer {
14
+ static normalize(response: TreeMappingResponse): TreeMappingResponse {
15
+ const skillsMapping = this.getOnlyValidSkills(response.skillsMapping)
16
+ const validIds = new Set(Object.keys(skillsMapping))
17
+ const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds)
18
+ return { ...response, skillsMapping, treeMapping }
19
+ }
20
+
21
+ static isSkillValid(skill: Skill) {
22
+ return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName))
23
+ }
24
+
25
+ private static getOnlyValidSkills(mapping: SkillsMapping): SkillsMapping {
26
+ return Object.fromEntries(
27
+ Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)),
28
+ )
29
+ }
30
+
31
+ private static removeEmptyNodes(treeMapping: TreeMapping, validIds: Set<string>): TreeMapping {
32
+ const emptyIds = this.getEmptyNodeIds(treeMapping, validIds)
33
+
34
+ return Object.fromEntries(
35
+ Object.entries(treeMapping)
36
+ .filter(([id]) => !emptyIds.has(id))
37
+ .map(([id, node]) => [
38
+ id,
39
+ {
40
+ ...node,
41
+ skills: node.skills.filter((sid) => validIds.has(sid)),
42
+ children: node.children.filter((cid) => !emptyIds.has(cid)),
43
+ },
44
+ ]),
45
+ )
46
+ }
47
+
48
+ private static getEmptyNodeIds(treeMapping: TreeMapping, validIds: Set<string>) {
49
+ const empty = new Set<string>()
50
+
51
+ const leafToRoot = Object.entries(treeMapping).sort(
52
+ ([, a], [, b]) => b.parents.length - a.parents.length,
53
+ )
54
+
55
+ for (const [id, node] of leafToRoot) {
56
+ const isEmptyLeaf = node.skills.length > 0 && node.skills.every((s) => !validIds.has(s))
57
+ const isEmptyParent = node.children.length > 0 && node.children.every((c) => empty.has(c))
58
+
59
+ if (isEmptyLeaf || isEmptyParent) empty.add(id)
60
+ }
61
+
62
+ return empty
63
+ }
64
+ }