placementt-core 1.400.1022 → 1.400.1024

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.
package/lib/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./surveys/types";
12
12
  export * from "./surveys/registry";
13
13
  export * from "./surveys/schedule";
14
14
  export * from "./skillsResolver";
15
+ export * from "./lmi";
15
16
  export * from "./productResolver";
16
17
  export * from "./groups";
17
18
  export * from "./emailSections";
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ __exportStar(require("./surveys/types"), exports);
32
32
  __exportStar(require("./surveys/registry"), exports);
33
33
  __exportStar(require("./surveys/schedule"), exports);
34
34
  __exportStar(require("./skillsResolver"), exports);
35
+ __exportStar(require("./lmi"), exports);
35
36
  __exportStar(require("./productResolver"), exports);
36
37
  __exportStar(require("./groups"), exports);
37
38
  __exportStar(require("./emailSections"), exports);
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,qDAAmC;AACnC,qDAAmC;AACnC,mDAAiC;AACjC,oDAAkC;AAClC,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,qDAAmC;AACnC,qDAAmC;AACnC,mDAAiC;AACjC,wCAAsB;AACtB,oDAAkC;AAClC,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
package/lib/lmi.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { JobRoleProfile } from "./callables/jobRoles";
2
+ import { LmiOccupation } from "./typeDefinitions";
3
+ /**
4
+ * The student-facing view of one LMI occupation.
5
+ *
6
+ * Lives in core because both readers now produce it: `jobRoles-getJobRoles` on
7
+ * the backend, and the "More information" popup on the web, which reads
8
+ * `lmiOccupations/{soc}` straight from Firestore rather than paying a cold
9
+ * function start to fetch one document by id. Shared so the two can't drift into
10
+ * showing a student different things depending on which door they came through.
11
+ *
12
+ * The shaping is presentation, not access control - the underlying data is
13
+ * public ONS / Nomis / IfATE reference data, and a signed-in client may read the
14
+ * collection. What it does is drop every field that means nothing to a
15
+ * fifteen-year-old (SOC codes, ONS region codes, source vintages) and rename the
16
+ * pay percentiles to words.
17
+ *
18
+ * @param {LmiOccupation} o the occupation document.
19
+ * @return {JobRoleProfile} the profile a student is shown.
20
+ */
21
+ export declare function studentJobRoleProfile(o: LmiOccupation): JobRoleProfile;
package/lib/lmi.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.studentJobRoleProfile = studentJobRoleProfile;
4
+ /**
5
+ * The student-facing view of one LMI occupation.
6
+ *
7
+ * Lives in core because both readers now produce it: `jobRoles-getJobRoles` on
8
+ * the backend, and the "More information" popup on the web, which reads
9
+ * `lmiOccupations/{soc}` straight from Firestore rather than paying a cold
10
+ * function start to fetch one document by id. Shared so the two can't drift into
11
+ * showing a student different things depending on which door they came through.
12
+ *
13
+ * The shaping is presentation, not access control - the underlying data is
14
+ * public ONS / Nomis / IfATE reference data, and a signed-in client may read the
15
+ * collection. What it does is drop every field that means nothing to a
16
+ * fifteen-year-old (SOC codes, ONS region codes, source vintages) and rename the
17
+ * pay percentiles to words.
18
+ *
19
+ * @param {LmiOccupation} o the occupation document.
20
+ * @return {JobRoleProfile} the profile a student is shown.
21
+ */
22
+ function studentJobRoleProfile(o) {
23
+ const national = o.salary?.national;
24
+ const salaryRegions = Object.values(o.salary?.byRegion ?? {})
25
+ .filter((r) => r.median !== null && r.median !== undefined)
26
+ .map((r) => ({ regionName: r.regionName, median: r.median }));
27
+ const employmentRegions = Object.values(o.employment?.byRegion ?? {})
28
+ .filter((r) => r.jobs !== null && r.jobs !== undefined)
29
+ .map((r) => ({ regionName: r.regionName, jobs: r.jobs }));
30
+ return {
31
+ soc: o.soc,
32
+ title: o.title,
33
+ description: o.description || undefined,
34
+ entryRoutes: o.entryRoutes || undefined,
35
+ ...(national ? {
36
+ salary: {
37
+ year: o.salary?.year,
38
+ lower: national.p10,
39
+ typical: national.median,
40
+ upper: national.p90,
41
+ ...(salaryRegions.length ? { byRegion: salaryRegions } : {}),
42
+ },
43
+ } : {}),
44
+ ...(employmentRegions.length ? {
45
+ employment: {
46
+ year: o.employment?.year,
47
+ byRegion: employmentRegions,
48
+ },
49
+ } : {}),
50
+ ...(o.skills?.length ? { skills: o.skills } : {}),
51
+ ...(o.apprenticeshipStandards?.length ? {
52
+ apprenticeshipStandards: o.apprenticeshipStandards
53
+ .map((s) => ({ name: s.name, level: s.level })),
54
+ } : {}),
55
+ };
56
+ }
57
+ //# sourceMappingURL=lmi.js.map
package/lib/lmi.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lmi.js","sourceRoot":"","sources":["../src/lmi.ts"],"names":[],"mappings":";;AAqBA,sDAmCC;AArDD;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,qBAAqB,CAAC,CAAgB;IAClD,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC;IACpC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;SACxD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;SAC1D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAC,CAAC,CAAC,CAAC;IAChE,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,QAAQ,IAAI,EAAE,CAAC;SAChE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;SACtD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC;IAE5D,OAAO;QACH,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;QACvC,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;QACvC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YACX,MAAM,EAAE;gBACJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI;gBACpB,KAAK,EAAE,QAAQ,CAAC,GAAG;gBACnB,OAAO,EAAE,QAAQ,CAAC,MAAM;gBACxB,KAAK,EAAE,QAAQ,CAAC,GAAG;gBACnB,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,aAAa,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7D;SACJ,CAAC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC3B,UAAU,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI;gBACxB,QAAQ,EAAE,iBAAiB;aAC9B;SACJ,CAAC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,CAAC,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,CAAC;YACpC,uBAAuB,EAAE,CAAC,CAAC,uBAAuB;iBAC7C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAC,CAAC,CAAC;SACpD,CAAC,CAAC,CAAC,EAAE,CAAC;KACV,CAAC;AACN,CAAC"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "private": false,
3
3
  "name": "placementt-core",
4
4
  "author": "Placementt",
5
- "version": "1.400.1022",
5
+ "version": "1.400.1024",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
8
  "scripts": {
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./surveys/types";
14
14
  export * from "./surveys/registry";
15
15
  export * from "./surveys/schedule";
16
16
  export * from "./skillsResolver";
17
+ export * from "./lmi";
17
18
  export * from "./productResolver";
18
19
  export * from "./groups";
19
20
  export * from "./emailSections";
package/src/lmi.ts ADDED
@@ -0,0 +1,57 @@
1
+ import {JobRoleProfile} from "./callables/jobRoles";
2
+ import {LmiOccupation} from "./typeDefinitions";
3
+
4
+ /**
5
+ * The student-facing view of one LMI occupation.
6
+ *
7
+ * Lives in core because both readers now produce it: `jobRoles-getJobRoles` on
8
+ * the backend, and the "More information" popup on the web, which reads
9
+ * `lmiOccupations/{soc}` straight from Firestore rather than paying a cold
10
+ * function start to fetch one document by id. Shared so the two can't drift into
11
+ * showing a student different things depending on which door they came through.
12
+ *
13
+ * The shaping is presentation, not access control - the underlying data is
14
+ * public ONS / Nomis / IfATE reference data, and a signed-in client may read the
15
+ * collection. What it does is drop every field that means nothing to a
16
+ * fifteen-year-old (SOC codes, ONS region codes, source vintages) and rename the
17
+ * pay percentiles to words.
18
+ *
19
+ * @param {LmiOccupation} o the occupation document.
20
+ * @return {JobRoleProfile} the profile a student is shown.
21
+ */
22
+ export function studentJobRoleProfile(o: LmiOccupation): JobRoleProfile {
23
+ const national = o.salary?.national;
24
+ const salaryRegions = Object.values(o.salary?.byRegion ?? {})
25
+ .filter((r) => r.median !== null && r.median !== undefined)
26
+ .map((r) => ({regionName: r.regionName, median: r.median}));
27
+ const employmentRegions = Object.values(o.employment?.byRegion ?? {})
28
+ .filter((r) => r.jobs !== null && r.jobs !== undefined)
29
+ .map((r) => ({regionName: r.regionName, jobs: r.jobs}));
30
+
31
+ return {
32
+ soc: o.soc,
33
+ title: o.title,
34
+ description: o.description || undefined,
35
+ entryRoutes: o.entryRoutes || undefined,
36
+ ...(national ? {
37
+ salary: {
38
+ year: o.salary?.year,
39
+ lower: national.p10,
40
+ typical: national.median,
41
+ upper: national.p90,
42
+ ...(salaryRegions.length ? {byRegion: salaryRegions} : {}),
43
+ },
44
+ } : {}),
45
+ ...(employmentRegions.length ? {
46
+ employment: {
47
+ year: o.employment?.year,
48
+ byRegion: employmentRegions,
49
+ },
50
+ } : {}),
51
+ ...(o.skills?.length ? {skills: o.skills} : {}),
52
+ ...(o.apprenticeshipStandards?.length ? {
53
+ apprenticeshipStandards: o.apprenticeshipStandards
54
+ .map((s) => ({name: s.name, level: s.level})),
55
+ } : {}),
56
+ };
57
+ }