placementt-core 1.400.1004 → 1.400.1005

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.
@@ -339,11 +339,17 @@ exports.flattenObject = flattenObject;
339
339
  const getGeoHash = async (data) => {
340
340
  if (!data?.["address-line1"] || !data.postal_code)
341
341
  return;
342
- const address = data?.["address-line1"] + " " + data?.["address-line2"] +
343
- " " + data?.locality + " " + data?.postal_code + " " + data?.country;
344
- address.replace(" ", "+");
342
+ const address = [
343
+ data["address-line1"],
344
+ data["address-line2"],
345
+ data.locality,
346
+ data.postal_code,
347
+ (0, exports.camelCaseToNormal)(data.country),
348
+ ].filter((part) => part).join(" ");
349
+ // Encode the address, otherwise characters like & or # in an address line
350
+ // terminate the query parameter and Google only sees the leading fragment.
345
351
  const apiQuery = "https://maps.googleapis.com/maps/api/geocode/json?address=" +
346
- address + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
352
+ encodeURIComponent(address) + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
347
353
  const location = await fetch(apiQuery)
348
354
  .then(async (res) => await res.json())
349
355
  .then((res) => {
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/firebase/util.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/firebase/util.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import { EmployerSharing, HubGroup, InstituteData, ProviderContactData } from "./typeDefinitions";
2
+ /**
3
+ * Hub groups: who belongs to a region, and who that lets an employer reach.
4
+ *
5
+ * A hub group is one entity that both schools and employers belong to, so "North"
6
+ * means the same North on both sides. Two edges hang off it, and they mean
7
+ * different things:
8
+ *
9
+ * - membership — what the member *is*. The hub writes it.
10
+ * schools: careersHubLinks[hubId].groups
11
+ * employers: savedBy[hubId].groups
12
+ * - sharing — who the employer said they want to work with. The employer
13
+ * writes it, and nothing else ever overwrites it: savedBy[hubId].sharing
14
+ *
15
+ * A hub that wants employers kept inside their own region sets
16
+ * `groupSettings.employerSharingScope = "membership"`. That narrows reach at
17
+ * resolve time rather than editing what the employer asked for, so dropping the
18
+ * setting again restores their original preference with no data to migrate back.
19
+ *
20
+ * Membership only ever narrows. An employer who consented to two named schools
21
+ * stays limited to those two schools when a hub drops them into a region holding
22
+ * forty — the intersection honours the employer, and the mismatch is reported as
23
+ * a conflict rather than silently resolving to nothing.
24
+ *
25
+ * Every surface resolves through here: the event fan-out, campaign audiences,
26
+ * school and employer pickers, and the employer-facing request page. They used to
27
+ * each re-query `careersHubLinks.{hub}.schoolGroups` by hand, which is why the
28
+ * clamp has one home.
29
+ */
30
+ /** Enough of a school to resolve membership, so callers can pass partials. */
31
+ export type SchoolGroupInput = Pick<InstituteData, "careersHubLinks">;
32
+ /** Enough of an employer to resolve, so callers can pass partials. */
33
+ export type EmployerGroupInput = Pick<ProviderContactData, "savedBy">;
34
+ export type EmployerReachConflict =
35
+ /** Membership left the employer reaching nobody, though they offered someone. */
36
+ "emptyReach" |
37
+ /** The hub put them in a group they never consented to work with. */
38
+ "membershipOutsideConsent";
39
+ export type ResolvedEmployerReach = {
40
+ /** Schools the employer reaches, after the clamp. */
41
+ schools: string[];
42
+ /** What the employer asked for, before the clamp. */
43
+ intended: string[];
44
+ /** True when membership removed schools the employer had offered to work with. */
45
+ clamped: boolean;
46
+ conflicts: EmployerReachConflict[];
47
+ /** Recorded onto dispatched requests so "why these schools in March?" is
48
+ * answerable in June, after the setting has changed twice. */
49
+ scope: "membership" | "unrestricted";
50
+ };
51
+ /** The hub's policy. Absent means unrestricted, which is how every hub behaved
52
+ * before group membership existed — so nothing changes until a hub opts in. */
53
+ export declare const getSharingScope: (hub?: Pick<InstituteData, "groupSettings">) => "membership" | "unrestricted";
54
+ /** School membership, falling back to the pre-migration field. Queries can't do
55
+ * this fallback, so the migration backfills `groups` and leaves `schoolGroups` in
56
+ * place; this covers anything read into memory before that has run. */
57
+ export declare const getSchoolGroupIds: (school: SchoolGroupInput | undefined, hubId: string) => string[];
58
+ /** Employer membership. No legacy fallback: `savedBy[hub].schoolGroups` was the
59
+ * employer's intent, not membership, and reading it as membership would silently
60
+ * turn a preference into a hub-assigned region. */
61
+ export declare const getEmployerGroupIds: (employer: EmployerGroupInput | undefined, hubId: string) => string[];
62
+ /** The employer's stated intent, migrating the legacy shape on read. An employer
63
+ * with no record of a preference is treated as having offered everyone, which is
64
+ * what the request form defaulted to before this existed. */
65
+ export declare const getEmployerSharing: (employer: EmployerGroupInput | undefined, hubId: string) => EmployerSharing;
66
+ /** Schools in a hub that have accepted their link. The gate on every resolution —
67
+ * an invited-but-not-joined school is not reachable however the groups fall. */
68
+ export declare const approvedHubSchools: (schools: {
69
+ [id: string]: SchoolGroupInput & {
70
+ careersHubLinks?: InstituteData["careersHubLinks"];
71
+ };
72
+ }, hubId: string) => string[];
73
+ /** Schools belonging to any of `groupIds`. Union, not intersection: a member of
74
+ * two regions reaches both. */
75
+ export declare const schoolsInGroups: (groupIds: string[], hubId: string, schools: {
76
+ [id: string]: SchoolGroupInput;
77
+ }) => string[];
78
+ /** The ceiling membership imposes. Unrestricted scope, or an employer the hub
79
+ * hasn't put in a group yet, means no ceiling — see `employerNeedsTriage` for why
80
+ * an ungrouped employer isn't clamped to nothing. */
81
+ export declare const permittedSchools: (employer: EmployerGroupInput | undefined, hubId: string, hub: Pick<InstituteData, "groupSettings"> | undefined, schools: {
82
+ [id: string]: SchoolGroupInput;
83
+ }) => string[];
84
+ /** An employer the hub has yet to place in a group, while scoping is on. Their
85
+ * request is accepted but held for the hub rather than fanned out — failing closed
86
+ * on submission would turn away brand-new employers, who are exactly the ones with
87
+ * no membership yet. Assigning them a group is what releases it. */
88
+ export declare const employerNeedsTriage: (employer: EmployerGroupInput | undefined, hubId: string, hub: Pick<InstituteData, "groupSettings"> | undefined) => boolean;
89
+ /**
90
+ * Where an employer's offer actually lands: their intent, narrowed by membership
91
+ * when the hub has asked for that, and always narrowed to approved schools.
92
+ */
93
+ export declare const resolveEmployerSchools: (employer: EmployerGroupInput | undefined, hubId: string, hub: Pick<InstituteData, "groupSettings"> | undefined, schools: {
94
+ [id: string]: SchoolGroupInput;
95
+ }) => ResolvedEmployerReach;
96
+ /** Both sides of a group, for management screens and pickers. */
97
+ export declare const resolveGroupMembers: (groupId: string, hubId: string, members: {
98
+ schools?: {
99
+ [id: string]: SchoolGroupInput;
100
+ };
101
+ employers?: {
102
+ [id: string]: EmployerGroupInput;
103
+ };
104
+ }) => {
105
+ schools: string[];
106
+ employers: string[];
107
+ };
108
+ /** Groups offered to a given member type. Absent `appliesTo` means schools only —
109
+ * every group created before employers had membership. */
110
+ export declare const groupsFor: (groups: {
111
+ [id: string]: HubGroup;
112
+ }, memberType: "school" | "employer") => {
113
+ [id: string]: HubGroup;
114
+ };
115
+ /** Of the groups an employer picked to work with, the ones that also make them a
116
+ * member. Picking "North" as somewhere you want to work is a statement that you
117
+ * belong there, so the hub doesn't have to file them by hand afterwards — but only
118
+ * for groups the hub marked as applying to employers. */
119
+ export declare const groupsGrantingMembership: (selectedGroupIds: string[], groups: {
120
+ [id: string]: HubGroup;
121
+ }) => string[];
package/lib/groups.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.groupsGrantingMembership = exports.groupsFor = exports.resolveGroupMembers = exports.resolveEmployerSchools = exports.employerNeedsTriage = exports.permittedSchools = exports.schoolsInGroups = exports.approvedHubSchools = exports.getEmployerSharing = exports.getEmployerGroupIds = exports.getSchoolGroupIds = exports.getSharingScope = void 0;
4
+ /** The hub's policy. Absent means unrestricted, which is how every hub behaved
5
+ * before group membership existed — so nothing changes until a hub opts in. */
6
+ const getSharingScope = (hub) => hub?.groupSettings?.employerSharingScope ?? "unrestricted";
7
+ exports.getSharingScope = getSharingScope;
8
+ /** School membership, falling back to the pre-migration field. Queries can't do
9
+ * this fallback, so the migration backfills `groups` and leaves `schoolGroups` in
10
+ * place; this covers anything read into memory before that has run. */
11
+ const getSchoolGroupIds = (school, hubId) => {
12
+ const link = school?.careersHubLinks?.[hubId];
13
+ return link?.groups ?? link?.schoolGroups ?? [];
14
+ };
15
+ exports.getSchoolGroupIds = getSchoolGroupIds;
16
+ /** Employer membership. No legacy fallback: `savedBy[hub].schoolGroups` was the
17
+ * employer's intent, not membership, and reading it as membership would silently
18
+ * turn a preference into a hub-assigned region. */
19
+ const getEmployerGroupIds = (employer, hubId) => employer?.savedBy?.[hubId]?.groups ?? [];
20
+ exports.getEmployerGroupIds = getEmployerGroupIds;
21
+ /** The employer's stated intent, migrating the legacy shape on read. An employer
22
+ * with no record of a preference is treated as having offered everyone, which is
23
+ * what the request form defaulted to before this existed. */
24
+ const getEmployerSharing = (employer, hubId) => {
25
+ const saved = employer?.savedBy?.[hubId];
26
+ if (saved?.sharing)
27
+ return saved.sharing;
28
+ const legacy = saved?.schoolGroups;
29
+ if (legacy && ((legacy.groups?.length ?? 0) > 0 || (legacy.specificSchools?.length ?? 0) > 0)) {
30
+ return { mode: "custom", groups: legacy.groups ?? [], specificSchools: legacy.specificSchools ?? [] };
31
+ }
32
+ return { mode: "all" };
33
+ };
34
+ exports.getEmployerSharing = getEmployerSharing;
35
+ const uniq = (ids) => [...new Set(ids)];
36
+ /** Schools in a hub that have accepted their link. The gate on every resolution —
37
+ * an invited-but-not-joined school is not reachable however the groups fall. */
38
+ const approvedHubSchools = (schools, hubId) => Object.entries(schools || {})
39
+ .filter(([, s]) => s?.careersHubLinks?.[hubId]?.status === "approved")
40
+ .map(([id]) => id);
41
+ exports.approvedHubSchools = approvedHubSchools;
42
+ /** Schools belonging to any of `groupIds`. Union, not intersection: a member of
43
+ * two regions reaches both. */
44
+ const schoolsInGroups = (groupIds, hubId, schools) => uniq(Object.entries(schools || {})
45
+ .filter(([, s]) => (0, exports.getSchoolGroupIds)(s, hubId).some((g) => groupIds.includes(g)))
46
+ .map(([id]) => id));
47
+ exports.schoolsInGroups = schoolsInGroups;
48
+ /** The ceiling membership imposes. Unrestricted scope, or an employer the hub
49
+ * hasn't put in a group yet, means no ceiling — see `employerNeedsTriage` for why
50
+ * an ungrouped employer isn't clamped to nothing. */
51
+ const permittedSchools = (employer, hubId, hub, schools) => {
52
+ const approved = (0, exports.approvedHubSchools)(schools, hubId);
53
+ if ((0, exports.getSharingScope)(hub) !== "membership")
54
+ return approved;
55
+ const membership = (0, exports.getEmployerGroupIds)(employer, hubId);
56
+ if (membership.length === 0)
57
+ return approved;
58
+ const inGroups = (0, exports.schoolsInGroups)(membership, hubId, schools);
59
+ return approved.filter((id) => inGroups.includes(id));
60
+ };
61
+ exports.permittedSchools = permittedSchools;
62
+ /** An employer the hub has yet to place in a group, while scoping is on. Their
63
+ * request is accepted but held for the hub rather than fanned out — failing closed
64
+ * on submission would turn away brand-new employers, who are exactly the ones with
65
+ * no membership yet. Assigning them a group is what releases it. */
66
+ const employerNeedsTriage = (employer, hubId, hub) => (0, exports.getSharingScope)(hub) === "membership" && (0, exports.getEmployerGroupIds)(employer, hubId).length === 0;
67
+ exports.employerNeedsTriage = employerNeedsTriage;
68
+ /**
69
+ * Where an employer's offer actually lands: their intent, narrowed by membership
70
+ * when the hub has asked for that, and always narrowed to approved schools.
71
+ */
72
+ const resolveEmployerSchools = (employer, hubId, hub, schools) => {
73
+ const scope = (0, exports.getSharingScope)(hub);
74
+ const approved = (0, exports.approvedHubSchools)(schools, hubId);
75
+ const sharing = (0, exports.getEmployerSharing)(employer, hubId);
76
+ const intended = sharing.mode === "all" ? approved : uniq([
77
+ ...(0, exports.schoolsInGroups)(sharing.groups ?? [], hubId, schools),
78
+ ...(sharing.specificSchools ?? []),
79
+ ]).filter((id) => approved.includes(id));
80
+ const permitted = (0, exports.permittedSchools)(employer, hubId, hub, schools);
81
+ const resolved = intended.filter((id) => permitted.includes(id));
82
+ const membership = (0, exports.getEmployerGroupIds)(employer, hubId);
83
+ const conflicts = [];
84
+ // Reported whatever the scope, because it's a fact about the employer's record
85
+ // rather than about the clamp: the hub filed them under a region they never
86
+ // agreed to work with, and will want to know before the setting is switched on.
87
+ if (sharing.mode === "custom" && membership.some((g) => !(sharing.groups ?? []).includes(g))) {
88
+ conflicts.push("membershipOutsideConsent");
89
+ }
90
+ if (intended.length > 0 && resolved.length === 0) {
91
+ conflicts.push("emptyReach");
92
+ }
93
+ return { schools: resolved, intended, clamped: resolved.length < intended.length, conflicts, scope };
94
+ };
95
+ exports.resolveEmployerSchools = resolveEmployerSchools;
96
+ /** Both sides of a group, for management screens and pickers. */
97
+ const resolveGroupMembers = (groupId, hubId, members) => ({
98
+ schools: Object.entries(members.schools || {})
99
+ .filter(([, s]) => (0, exports.getSchoolGroupIds)(s, hubId).includes(groupId))
100
+ .map(([id]) => id),
101
+ employers: Object.entries(members.employers || {})
102
+ .filter(([, e]) => (0, exports.getEmployerGroupIds)(e, hubId).includes(groupId))
103
+ .map(([id]) => id),
104
+ });
105
+ exports.resolveGroupMembers = resolveGroupMembers;
106
+ /** Groups offered to a given member type. Absent `appliesTo` means schools only —
107
+ * every group created before employers had membership. */
108
+ const groupsFor = (groups, memberType) => Object.fromEntries(Object.entries(groups || {})
109
+ .filter(([, g]) => (g.appliesTo ?? ["school"]).includes(memberType)));
110
+ exports.groupsFor = groupsFor;
111
+ /** Of the groups an employer picked to work with, the ones that also make them a
112
+ * member. Picking "North" as somewhere you want to work is a statement that you
113
+ * belong there, so the hub doesn't have to file them by hand afterwards — but only
114
+ * for groups the hub marked as applying to employers. */
115
+ const groupsGrantingMembership = (selectedGroupIds, groups) => selectedGroupIds.filter((id) => (groups?.[id]?.appliesTo ?? ["school"]).includes("employer"));
116
+ exports.groupsGrantingMembership = groupsGrantingMembership;
117
+ //# sourceMappingURL=groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../src/groups.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const groups_1 = require("./groups");
4
+ /**
5
+ * The clamp is the point of these tests. It has to narrow without ever editing the
6
+ * employer's stated preference, and it has to stay reversible — switch scoping off
7
+ * and the employer's original offer must come back untouched.
8
+ */
9
+ const HUB = "hub1";
10
+ const school = (groups, status = "approved") => ({
11
+ careersHubLinks: { [HUB]: { exists: true, invited: "", status, groups } },
12
+ });
13
+ const schools = {
14
+ north1: school(["north"]),
15
+ north2: school(["north"]),
16
+ south1: school(["south"]),
17
+ both1: school(["north", "south"]),
18
+ ungrouped: school([]),
19
+ pending: school(["north"], "invited"),
20
+ };
21
+ const employer = (saved) => ({
22
+ savedBy: { [HUB]: { exists: true, status: "approved", ...saved } },
23
+ });
24
+ const unrestricted = {};
25
+ const scoped = { groupSettings: { employerSharingScope: "membership" } };
26
+ describe("membership reads", () => {
27
+ it("falls back to the pre-migration school field", () => {
28
+ const legacy = { careersHubLinks: { [HUB]: { schoolGroups: ["north"] } } };
29
+ expect((0, groups_1.getSchoolGroupIds)(legacy, HUB)).toEqual(["north"]);
30
+ });
31
+ it("prefers the migrated field when both are present", () => {
32
+ const both = { careersHubLinks: { [HUB]: { groups: ["south"], schoolGroups: ["north"] } } };
33
+ expect((0, groups_1.getSchoolGroupIds)(both, HUB)).toEqual(["south"]);
34
+ });
35
+ it("reads legacy employer sharing as a custom preference, not as membership", () => {
36
+ const e = employer({ schoolGroups: { groups: ["north"], specificSchools: ["south1"] } });
37
+ expect((0, groups_1.getEmployerSharing)(e, HUB)).toEqual({ mode: "custom", groups: ["north"], specificSchools: ["south1"] });
38
+ // The legacy field must never become membership — that would turn a
39
+ // preference the employer set into a region the hub assigned.
40
+ expect((0, groups_1.permittedSchools)(e, HUB, scoped, schools)).toEqual(expect.arrayContaining(["north1", "south1"]));
41
+ });
42
+ it("treats an employer with no record as having offered everyone", () => {
43
+ expect((0, groups_1.getEmployerSharing)(employer({}), HUB)).toEqual({ mode: "all" });
44
+ });
45
+ });
46
+ describe("resolveEmployerSchools", () => {
47
+ it("reaches every approved school when unrestricted and offering all", () => {
48
+ const r = (0, groups_1.resolveEmployerSchools)(employer({ sharing: { mode: "all" } }), HUB, unrestricted, schools);
49
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2", "south1", "ungrouped"]);
50
+ expect(r.clamped).toBe(false);
51
+ });
52
+ it("never reaches a school that has not accepted the hub link", () => {
53
+ const r = (0, groups_1.resolveEmployerSchools)(employer({ sharing: { mode: "all" } }), HUB, unrestricted, schools);
54
+ expect(r.schools).not.toContain("pending");
55
+ });
56
+ it("clamps an 'all' offer to the employer's own region when scoping is on", () => {
57
+ const e = employer({ sharing: { mode: "all" }, groups: ["north"] });
58
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
59
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2"]);
60
+ expect(r.clamped).toBe(true);
61
+ expect(r.scope).toBe("membership");
62
+ });
63
+ it("restores the original offer when the hub drops the clamp", () => {
64
+ const e = employer({ sharing: { mode: "all" }, groups: ["north"] });
65
+ expect((0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools).schools).not.toContain("south1");
66
+ // Same employer document, no migration — only the hub setting changed.
67
+ expect((0, groups_1.resolveEmployerSchools)(e, HUB, unrestricted, schools).schools).toContain("south1");
68
+ });
69
+ it("honours specific schools over a wider membership", () => {
70
+ // The hub filed them under North, which holds four schools. They agreed to
71
+ // two. Membership narrows; it must not widen them back to the region.
72
+ const e = employer({ sharing: { mode: "custom", specificSchools: ["north1"] }, groups: ["north"] });
73
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
74
+ expect(r.schools).toEqual(["north1"]);
75
+ });
76
+ it("flags membership the employer never consented to", () => {
77
+ const e = employer({ sharing: { mode: "custom", groups: ["north"] }, groups: ["south"] });
78
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
79
+ expect(r.conflicts).toContain("membershipOutsideConsent");
80
+ });
81
+ it("flags it whatever the scope, because it is a fact about the record", () => {
82
+ const e = employer({ sharing: { mode: "custom", groups: ["north"] }, groups: ["south"] });
83
+ expect((0, groups_1.resolveEmployerSchools)(e, HUB, unrestricted, schools).conflicts)
84
+ .toContain("membershipOutsideConsent");
85
+ });
86
+ it("keeps schools that sit in both the consented and the assigned region", () => {
87
+ // Consented to North, filed under South: both1 belongs to each, so the
88
+ // employer legitimately still reaches it and there is nothing to flag.
89
+ const e = employer({ sharing: { mode: "custom", groups: ["north"] }, groups: ["south"] });
90
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
91
+ expect(r.schools).toEqual(["both1"]);
92
+ expect(r.conflicts).not.toContain("emptyReach");
93
+ });
94
+ it("flags an offer that membership has narrowed to nobody", () => {
95
+ const e = employer({ sharing: { mode: "custom", specificSchools: ["north1"] }, groups: ["south"] });
96
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
97
+ expect(r.schools).toEqual([]);
98
+ expect(r.conflicts).toContain("emptyReach");
99
+ });
100
+ it("does not flag an empty reach when the employer offered nobody", () => {
101
+ const e = employer({ sharing: { mode: "custom", groups: [] }, groups: ["north"] });
102
+ expect((0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools).conflicts).not.toContain("emptyReach");
103
+ });
104
+ it("unions across an employer's regions rather than intersecting them", () => {
105
+ const e = employer({ sharing: { mode: "all" }, groups: ["north", "south"] });
106
+ const r = (0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools);
107
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2", "south1"]);
108
+ });
109
+ it("leaves an ungrouped employer unclamped, for triage instead", () => {
110
+ const e = employer({ sharing: { mode: "all" } });
111
+ expect((0, groups_1.resolveEmployerSchools)(e, HUB, scoped, schools).clamped).toBe(false);
112
+ expect((0, groups_1.employerNeedsTriage)(e, HUB, scoped)).toBe(true);
113
+ });
114
+ it("does not hold an ungrouped employer when the hub is unrestricted", () => {
115
+ expect((0, groups_1.employerNeedsTriage)(employer({}), HUB, unrestricted)).toBe(false);
116
+ });
117
+ });
118
+ describe("group membership helpers", () => {
119
+ const groups = {
120
+ north: { name: "North", careersHubId: HUB, appliesTo: ["school", "employer"] },
121
+ legacy: { name: "Legacy", careersHubId: HUB },
122
+ stem: { name: "STEM", careersHubId: HUB, appliesTo: ["employer"] },
123
+ };
124
+ it("treats a group with no appliesTo as schools only", () => {
125
+ expect(Object.keys((0, groups_1.groupsFor)(groups, "school")).sort()).toEqual(["legacy", "north"]);
126
+ expect(Object.keys((0, groups_1.groupsFor)(groups, "employer")).sort()).toEqual(["north", "stem"]);
127
+ });
128
+ it("grants membership only for groups the hub opened to employers", () => {
129
+ expect((0, groups_1.groupsGrantingMembership)(["north", "legacy"], groups)).toEqual(["north"]);
130
+ });
131
+ it("lists both sides of a group", () => {
132
+ const employers = { e1: employer({ groups: ["north"] }), e2: employer({ groups: ["south"] }) };
133
+ const members = (0, groups_1.resolveGroupMembers)("north", HUB, { schools, employers });
134
+ expect(members.schools.sort()).toEqual(["both1", "north1", "north2", "pending"]);
135
+ expect(members.employers).toEqual(["e1"]);
136
+ });
137
+ });
138
+ //# sourceMappingURL=groups.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.test.js","sourceRoot":"","sources":["../src/groups.test.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./surveys/registry";
12
12
  export * from "./surveys/schedule";
13
13
  export * from "./skillsResolver";
14
14
  export * from "./productResolver";
15
+ export * from "./groups";
15
16
  export * from "./emailSections";
16
17
  export * from "./exportTransformers";
17
18
  export * from "./compassExport";
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ __exportStar(require("./surveys/registry"), exports);
32
32
  __exportStar(require("./surveys/schedule"), exports);
33
33
  __exportStar(require("./skillsResolver"), exports);
34
34
  __exportStar(require("./productResolver"), exports);
35
+ __exportStar(require("./groups"), exports);
35
36
  __exportStar(require("./emailSections"), exports);
36
37
  __exportStar(require("./exportTransformers"), exports);
37
38
  __exportStar(require("./compassExport"), 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,kDAAgC;AAChC,qDAAmC;AACnC,qDAAmC;AACnC,mDAAiC;AACjC,oDAAkC;AAClC,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,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,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,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"}
@@ -812,10 +812,17 @@ export type ProviderContactData = {
812
812
  providerConsentDate?: string;
813
813
  MATschools?: string[];
814
814
  notes?: Descendant[];
815
+ /** @deprecated The employer's sharing intent, migrated to `sharing`. Kept so
816
+ * anything not yet migrated still resolves — read it via `getEmployerSharing`,
817
+ * never directly. */
815
818
  schoolGroups?: {
816
819
  groups?: string[];
817
820
  specificSchools?: string[];
818
821
  };
822
+ /** Hub groups this employer belongs to. Written by the hub only. */
823
+ groups?: string[];
824
+ /** Who the employer wants to work with. Written by the employer only. */
825
+ sharing?: EmployerSharing;
819
826
  additionalData?: {
820
827
  [key: string]: unknown;
821
828
  };
@@ -877,7 +884,10 @@ export type InstituteData = {
877
884
  exists: boolean;
878
885
  invited: string;
879
886
  status: "invited" | "approved" | "declined";
887
+ /** @deprecated Migrated to `groups`. Read via `getSchoolGroupIds`. */
880
888
  schoolGroups?: string[];
889
+ /** Hub groups this school belongs to. */
890
+ groups?: string[];
881
891
  notes?: Descendant[];
882
892
  emailsSent?: {
883
893
  sent?: Timestamp;
@@ -904,6 +914,13 @@ export type InstituteData = {
904
914
  connectionToken: string;
905
915
  fields?: string[];
906
916
  };
917
+ /** Careers hub policy for group membership. `employerSharingScope: "membership"`
918
+ * narrows what an employer reaches to the schools in the employer's own groups,
919
+ * without editing what the employer asked for — drop back to "unrestricted" and
920
+ * their original preference takes effect again. */
921
+ groupSettings?: {
922
+ employerSharingScope: "membership" | "unrestricted";
923
+ };
907
924
  emailDomain: string;
908
925
  splitBilling?: boolean;
909
926
  adminBillingContactId?: string;
@@ -1679,7 +1696,9 @@ export type SchoolData = OrganisationAddress & {
1679
1696
  exists: boolean;
1680
1697
  invited: string;
1681
1698
  status: "invited" | "approved" | "declined";
1699
+ /** @deprecated Migrated to `groups`. Read via `getSchoolGroupIds`. */
1682
1700
  schoolGroups?: string[];
1701
+ groups?: string[];
1683
1702
  emailsSent?: {
1684
1703
  sent?: Timestamp;
1685
1704
  log: {
@@ -1691,9 +1710,29 @@ export type SchoolData = OrganisationAddress & {
1691
1710
  };
1692
1711
  };
1693
1712
  };
1694
- export type SchoolGroup = {
1713
+ /** A group a Careers Hub can assign both schools and employers to — a region,
1714
+ * most often. Stored in the `hubGroups` collection (migrated from `schoolGroups`,
1715
+ * keeping the same document IDs so every existing membership array still resolves). */
1716
+ export type HubGroup = {
1695
1717
  name: string;
1696
1718
  careersHubId: string;
1719
+ /** Which member types this group can be assigned to. Absent means schools only,
1720
+ * which is what every group created before employers had membership was. */
1721
+ appliesTo?: ("school" | "employer")[];
1722
+ /** Regions are usually exclusive — a member belongs to one. Enforced in the UI
1723
+ * as single-select; the data stays an array either way. */
1724
+ exclusive?: boolean;
1725
+ };
1726
+ /** @deprecated Renamed to HubGroup now that employers are members too. */
1727
+ export type SchoolGroup = HubGroup;
1728
+ /** Who an employer told a hub they want to work with. Written by the employer, and
1729
+ * never overwritten by the hub — the hub expresses its policy through group
1730
+ * membership plus `InstituteData.groupSettings`, which narrows this at resolve time.
1731
+ * See `resolveEmployerSchools`. */
1732
+ export type EmployerSharing = {
1733
+ mode: "all" | "custom";
1734
+ groups?: string[];
1735
+ specificSchools?: string[];
1697
1736
  };
1698
1737
  export type ExternalEvent = {
1699
1738
  name: string;
@@ -1921,6 +1960,16 @@ export type ExternalEventRequest = {
1921
1960
  schoolSelectionType?: "allSchools" | "selectGroups" | "specificSchools";
1922
1961
  schools?: string[];
1923
1962
  schoolGroups?: string[];
1963
+ /** The schools this request actually reached, frozen at dispatch. Resolution is
1964
+ * live everywhere else, so without this a hub that later widens its scoping would
1965
+ * have no record of who was reached under the old policy — and nothing stops a
1966
+ * historical offer being silently re-fanned-out. */
1967
+ resolvedSchools?: string[];
1968
+ resolvedAt?: string;
1969
+ resolvedUnderScope?: "membership" | "unrestricted";
1970
+ /** Set when membership narrowed the employer's stated preference, so the hub can
1971
+ * see the offer was wider than what went out. */
1972
+ resolvedClamped?: boolean;
1924
1973
  numberSharedWith?: number;
1925
1974
  maxSchools?: number;
1926
1975
  viewedBy?: {
@@ -2820,7 +2869,10 @@ export type CareersHubInvite = {
2820
2869
  schoolName: string;
2821
2870
  invited: string;
2822
2871
  status: "invited" | "approved" | "declined";
2872
+ /** @deprecated Migrated to `groups`, and carried onto the school's
2873
+ * careersHubLinks entry on registration. */
2823
2874
  schoolGroups?: string[];
2875
+ groups?: string[];
2824
2876
  emailsSent?: {
2825
2877
  sent?: Timestamp;
2826
2878
  log: {
@@ -2838,7 +2890,9 @@ export type TrustInvite = {
2838
2890
  schoolName: string;
2839
2891
  invited: string;
2840
2892
  status: "invited" | "approved" | "declined";
2893
+ /** @deprecated Migrated to `groups`. */
2841
2894
  schoolGroups?: string[];
2895
+ groups?: string[];
2842
2896
  emailsSent?: {
2843
2897
  sent?: Timestamp;
2844
2898
  log: {
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.1004",
5
+ "version": "1.400.1005",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
8
  "scripts": {
@@ -343,11 +343,17 @@ export const flattenObject = (obj) => {
343
343
 
344
344
  export const getGeoHash = async (data:Partial<Address>) => {
345
345
  if (!data?.["address-line1"] || !data.postal_code) return;
346
- const address = data?.["address-line1"] + " " + data?.["address-line2"] +
347
- " " + data?.locality + " " + data?.postal_code + " " + data?.country;
348
- address.replace(" ", "+");
346
+ const address = [
347
+ data["address-line1"],
348
+ data["address-line2"],
349
+ data.locality,
350
+ data.postal_code,
351
+ camelCaseToNormal(data.country),
352
+ ].filter((part) => part).join(" ");
353
+ // Encode the address, otherwise characters like & or # in an address line
354
+ // terminate the query parameter and Google only sees the leading fragment.
349
355
  const apiQuery = "https://maps.googleapis.com/maps/api/geocode/json?address=" +
350
- address + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
356
+ encodeURIComponent(address) + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
351
357
 
352
358
  const location = await fetch(apiQuery)
353
359
  .then(async (res) =>
@@ -0,0 +1,173 @@
1
+ import {
2
+ employerNeedsTriage,
3
+ getEmployerSharing,
4
+ getSchoolGroupIds,
5
+ groupsFor,
6
+ groupsGrantingMembership,
7
+ permittedSchools,
8
+ resolveEmployerSchools,
9
+ resolveGroupMembers,
10
+ } from "./groups";
11
+ import {HubGroup, InstituteData, ProviderContactData} from "./typeDefinitions";
12
+
13
+ /**
14
+ * The clamp is the point of these tests. It has to narrow without ever editing the
15
+ * employer's stated preference, and it has to stay reversible — switch scoping off
16
+ * and the employer's original offer must come back untouched.
17
+ */
18
+
19
+ const HUB = "hub1";
20
+
21
+ const school = (groups: string[], status: "approved"|"invited" = "approved") => ({
22
+ careersHubLinks: {[HUB]: {exists: true, invited: "", status, groups}},
23
+ }) as unknown as InstituteData;
24
+
25
+ const schools = {
26
+ north1: school(["north"]),
27
+ north2: school(["north"]),
28
+ south1: school(["south"]),
29
+ both1: school(["north", "south"]),
30
+ ungrouped: school([]),
31
+ pending: school(["north"], "invited"),
32
+ };
33
+
34
+ const employer = (saved: Record<string, unknown>) => ({
35
+ savedBy: {[HUB]: {exists: true, status: "approved", ...saved}},
36
+ }) as unknown as ProviderContactData;
37
+
38
+ const unrestricted = {} as InstituteData;
39
+ const scoped = {groupSettings: {employerSharingScope: "membership"}} as InstituteData;
40
+
41
+ describe("membership reads", () => {
42
+ it("falls back to the pre-migration school field", () => {
43
+ const legacy = {careersHubLinks: {[HUB]: {schoolGroups: ["north"]}}} as unknown as InstituteData;
44
+ expect(getSchoolGroupIds(legacy, HUB)).toEqual(["north"]);
45
+ });
46
+
47
+ it("prefers the migrated field when both are present", () => {
48
+ const both = {careersHubLinks: {[HUB]: {groups: ["south"], schoolGroups: ["north"]}}} as unknown as InstituteData;
49
+ expect(getSchoolGroupIds(both, HUB)).toEqual(["south"]);
50
+ });
51
+
52
+ it("reads legacy employer sharing as a custom preference, not as membership", () => {
53
+ const e = employer({schoolGroups: {groups: ["north"], specificSchools: ["south1"]}});
54
+ expect(getEmployerSharing(e, HUB)).toEqual({mode: "custom", groups: ["north"], specificSchools: ["south1"]});
55
+ // The legacy field must never become membership — that would turn a
56
+ // preference the employer set into a region the hub assigned.
57
+ expect(permittedSchools(e, HUB, scoped, schools)).toEqual(
58
+ expect.arrayContaining(["north1", "south1"]));
59
+ });
60
+
61
+ it("treats an employer with no record as having offered everyone", () => {
62
+ expect(getEmployerSharing(employer({}), HUB)).toEqual({mode: "all"});
63
+ });
64
+ });
65
+
66
+ describe("resolveEmployerSchools", () => {
67
+ it("reaches every approved school when unrestricted and offering all", () => {
68
+ const r = resolveEmployerSchools(employer({sharing: {mode: "all"}}), HUB, unrestricted, schools);
69
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2", "south1", "ungrouped"]);
70
+ expect(r.clamped).toBe(false);
71
+ });
72
+
73
+ it("never reaches a school that has not accepted the hub link", () => {
74
+ const r = resolveEmployerSchools(employer({sharing: {mode: "all"}}), HUB, unrestricted, schools);
75
+ expect(r.schools).not.toContain("pending");
76
+ });
77
+
78
+ it("clamps an 'all' offer to the employer's own region when scoping is on", () => {
79
+ const e = employer({sharing: {mode: "all"}, groups: ["north"]});
80
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
81
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2"]);
82
+ expect(r.clamped).toBe(true);
83
+ expect(r.scope).toBe("membership");
84
+ });
85
+
86
+ it("restores the original offer when the hub drops the clamp", () => {
87
+ const e = employer({sharing: {mode: "all"}, groups: ["north"]});
88
+ expect(resolveEmployerSchools(e, HUB, scoped, schools).schools).not.toContain("south1");
89
+ // Same employer document, no migration — only the hub setting changed.
90
+ expect(resolveEmployerSchools(e, HUB, unrestricted, schools).schools).toContain("south1");
91
+ });
92
+
93
+ it("honours specific schools over a wider membership", () => {
94
+ // The hub filed them under North, which holds four schools. They agreed to
95
+ // two. Membership narrows; it must not widen them back to the region.
96
+ const e = employer({sharing: {mode: "custom", specificSchools: ["north1"]}, groups: ["north"]});
97
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
98
+ expect(r.schools).toEqual(["north1"]);
99
+ });
100
+
101
+ it("flags membership the employer never consented to", () => {
102
+ const e = employer({sharing: {mode: "custom", groups: ["north"]}, groups: ["south"]});
103
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
104
+ expect(r.conflicts).toContain("membershipOutsideConsent");
105
+ });
106
+
107
+ it("flags it whatever the scope, because it is a fact about the record", () => {
108
+ const e = employer({sharing: {mode: "custom", groups: ["north"]}, groups: ["south"]});
109
+ expect(resolveEmployerSchools(e, HUB, unrestricted, schools).conflicts)
110
+ .toContain("membershipOutsideConsent");
111
+ });
112
+
113
+ it("keeps schools that sit in both the consented and the assigned region", () => {
114
+ // Consented to North, filed under South: both1 belongs to each, so the
115
+ // employer legitimately still reaches it and there is nothing to flag.
116
+ const e = employer({sharing: {mode: "custom", groups: ["north"]}, groups: ["south"]});
117
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
118
+ expect(r.schools).toEqual(["both1"]);
119
+ expect(r.conflicts).not.toContain("emptyReach");
120
+ });
121
+
122
+ it("flags an offer that membership has narrowed to nobody", () => {
123
+ const e = employer({sharing: {mode: "custom", specificSchools: ["north1"]}, groups: ["south"]});
124
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
125
+ expect(r.schools).toEqual([]);
126
+ expect(r.conflicts).toContain("emptyReach");
127
+ });
128
+
129
+ it("does not flag an empty reach when the employer offered nobody", () => {
130
+ const e = employer({sharing: {mode: "custom", groups: []}, groups: ["north"]});
131
+ expect(resolveEmployerSchools(e, HUB, scoped, schools).conflicts).not.toContain("emptyReach");
132
+ });
133
+
134
+ it("unions across an employer's regions rather than intersecting them", () => {
135
+ const e = employer({sharing: {mode: "all"}, groups: ["north", "south"]});
136
+ const r = resolveEmployerSchools(e, HUB, scoped, schools);
137
+ expect(r.schools.sort()).toEqual(["both1", "north1", "north2", "south1"]);
138
+ });
139
+
140
+ it("leaves an ungrouped employer unclamped, for triage instead", () => {
141
+ const e = employer({sharing: {mode: "all"}});
142
+ expect(resolveEmployerSchools(e, HUB, scoped, schools).clamped).toBe(false);
143
+ expect(employerNeedsTriage(e, HUB, scoped)).toBe(true);
144
+ });
145
+
146
+ it("does not hold an ungrouped employer when the hub is unrestricted", () => {
147
+ expect(employerNeedsTriage(employer({}), HUB, unrestricted)).toBe(false);
148
+ });
149
+ });
150
+
151
+ describe("group membership helpers", () => {
152
+ const groups: {[id: string]: HubGroup} = {
153
+ north: {name: "North", careersHubId: HUB, appliesTo: ["school", "employer"]},
154
+ legacy: {name: "Legacy", careersHubId: HUB},
155
+ stem: {name: "STEM", careersHubId: HUB, appliesTo: ["employer"]},
156
+ };
157
+
158
+ it("treats a group with no appliesTo as schools only", () => {
159
+ expect(Object.keys(groupsFor(groups, "school")).sort()).toEqual(["legacy", "north"]);
160
+ expect(Object.keys(groupsFor(groups, "employer")).sort()).toEqual(["north", "stem"]);
161
+ });
162
+
163
+ it("grants membership only for groups the hub opened to employers", () => {
164
+ expect(groupsGrantingMembership(["north", "legacy"], groups)).toEqual(["north"]);
165
+ });
166
+
167
+ it("lists both sides of a group", () => {
168
+ const employers = {e1: employer({groups: ["north"]}), e2: employer({groups: ["south"]})};
169
+ const members = resolveGroupMembers("north", HUB, {schools, employers});
170
+ expect(members.schools.sort()).toEqual(["both1", "north1", "north2", "pending"]);
171
+ expect(members.employers).toEqual(["e1"]);
172
+ });
173
+ });
package/src/groups.ts ADDED
@@ -0,0 +1,215 @@
1
+ import {EmployerSharing, HubGroup, InstituteData, ProviderContactData} from "./typeDefinitions";
2
+
3
+ /**
4
+ * Hub groups: who belongs to a region, and who that lets an employer reach.
5
+ *
6
+ * A hub group is one entity that both schools and employers belong to, so "North"
7
+ * means the same North on both sides. Two edges hang off it, and they mean
8
+ * different things:
9
+ *
10
+ * - membership — what the member *is*. The hub writes it.
11
+ * schools: careersHubLinks[hubId].groups
12
+ * employers: savedBy[hubId].groups
13
+ * - sharing — who the employer said they want to work with. The employer
14
+ * writes it, and nothing else ever overwrites it: savedBy[hubId].sharing
15
+ *
16
+ * A hub that wants employers kept inside their own region sets
17
+ * `groupSettings.employerSharingScope = "membership"`. That narrows reach at
18
+ * resolve time rather than editing what the employer asked for, so dropping the
19
+ * setting again restores their original preference with no data to migrate back.
20
+ *
21
+ * Membership only ever narrows. An employer who consented to two named schools
22
+ * stays limited to those two schools when a hub drops them into a region holding
23
+ * forty — the intersection honours the employer, and the mismatch is reported as
24
+ * a conflict rather than silently resolving to nothing.
25
+ *
26
+ * Every surface resolves through here: the event fan-out, campaign audiences,
27
+ * school and employer pickers, and the employer-facing request page. They used to
28
+ * each re-query `careersHubLinks.{hub}.schoolGroups` by hand, which is why the
29
+ * clamp has one home.
30
+ */
31
+
32
+ /** Enough of a school to resolve membership, so callers can pass partials. */
33
+ export type SchoolGroupInput = Pick<InstituteData, "careersHubLinks">;
34
+
35
+ /** Enough of an employer to resolve, so callers can pass partials. */
36
+ export type EmployerGroupInput = Pick<ProviderContactData, "savedBy">;
37
+
38
+ export type EmployerReachConflict =
39
+ /** Membership left the employer reaching nobody, though they offered someone. */
40
+ "emptyReach"|
41
+ /** The hub put them in a group they never consented to work with. */
42
+ "membershipOutsideConsent";
43
+
44
+ export type ResolvedEmployerReach = {
45
+ /** Schools the employer reaches, after the clamp. */
46
+ schools: string[],
47
+ /** What the employer asked for, before the clamp. */
48
+ intended: string[],
49
+ /** True when membership removed schools the employer had offered to work with. */
50
+ clamped: boolean,
51
+ conflicts: EmployerReachConflict[],
52
+ /** Recorded onto dispatched requests so "why these schools in March?" is
53
+ * answerable in June, after the setting has changed twice. */
54
+ scope: "membership"|"unrestricted",
55
+ };
56
+
57
+ /** The hub's policy. Absent means unrestricted, which is how every hub behaved
58
+ * before group membership existed — so nothing changes until a hub opts in. */
59
+ export const getSharingScope = (hub?: Pick<InstituteData, "groupSettings">) =>
60
+ hub?.groupSettings?.employerSharingScope ?? "unrestricted";
61
+
62
+ /** School membership, falling back to the pre-migration field. Queries can't do
63
+ * this fallback, so the migration backfills `groups` and leaves `schoolGroups` in
64
+ * place; this covers anything read into memory before that has run. */
65
+ export const getSchoolGroupIds = (school: SchoolGroupInput|undefined, hubId: string): string[] => {
66
+ const link = school?.careersHubLinks?.[hubId];
67
+ return link?.groups ?? link?.schoolGroups ?? [];
68
+ };
69
+
70
+ /** Employer membership. No legacy fallback: `savedBy[hub].schoolGroups` was the
71
+ * employer's intent, not membership, and reading it as membership would silently
72
+ * turn a preference into a hub-assigned region. */
73
+ export const getEmployerGroupIds = (employer: EmployerGroupInput|undefined, hubId: string): string[] =>
74
+ employer?.savedBy?.[hubId]?.groups ?? [];
75
+
76
+ /** The employer's stated intent, migrating the legacy shape on read. An employer
77
+ * with no record of a preference is treated as having offered everyone, which is
78
+ * what the request form defaulted to before this existed. */
79
+ export const getEmployerSharing = (employer: EmployerGroupInput|undefined, hubId: string): EmployerSharing => {
80
+ const saved = employer?.savedBy?.[hubId];
81
+ if (saved?.sharing) return saved.sharing;
82
+
83
+ const legacy = saved?.schoolGroups;
84
+ if (legacy && ((legacy.groups?.length ?? 0) > 0 || (legacy.specificSchools?.length ?? 0) > 0)) {
85
+ return {mode: "custom", groups: legacy.groups ?? [], specificSchools: legacy.specificSchools ?? []};
86
+ }
87
+ return {mode: "all"};
88
+ };
89
+
90
+ const uniq = (ids: string[]) => [...new Set(ids)];
91
+
92
+ /** Schools in a hub that have accepted their link. The gate on every resolution —
93
+ * an invited-but-not-joined school is not reachable however the groups fall. */
94
+ export const approvedHubSchools = (
95
+ schools: {[id: string]: SchoolGroupInput&{careersHubLinks?: InstituteData["careersHubLinks"]}},
96
+ hubId: string
97
+ ): string[] =>
98
+ Object.entries(schools || {})
99
+ .filter(([, s]) => s?.careersHubLinks?.[hubId]?.status === "approved")
100
+ .map(([id]) => id);
101
+
102
+ /** Schools belonging to any of `groupIds`. Union, not intersection: a member of
103
+ * two regions reaches both. */
104
+ export const schoolsInGroups = (
105
+ groupIds: string[],
106
+ hubId: string,
107
+ schools: {[id: string]: SchoolGroupInput}
108
+ ): string[] =>
109
+ uniq(Object.entries(schools || {})
110
+ .filter(([, s]) => getSchoolGroupIds(s, hubId).some((g) => groupIds.includes(g)))
111
+ .map(([id]) => id));
112
+
113
+ /** The ceiling membership imposes. Unrestricted scope, or an employer the hub
114
+ * hasn't put in a group yet, means no ceiling — see `employerNeedsTriage` for why
115
+ * an ungrouped employer isn't clamped to nothing. */
116
+ export const permittedSchools = (
117
+ employer: EmployerGroupInput|undefined,
118
+ hubId: string,
119
+ hub: Pick<InstituteData, "groupSettings">|undefined,
120
+ schools: {[id: string]: SchoolGroupInput}
121
+ ): string[] => {
122
+ const approved = approvedHubSchools(schools, hubId);
123
+ if (getSharingScope(hub) !== "membership") return approved;
124
+
125
+ const membership = getEmployerGroupIds(employer, hubId);
126
+ if (membership.length === 0) return approved;
127
+
128
+ const inGroups = schoolsInGroups(membership, hubId, schools);
129
+ return approved.filter((id) => inGroups.includes(id));
130
+ };
131
+
132
+ /** An employer the hub has yet to place in a group, while scoping is on. Their
133
+ * request is accepted but held for the hub rather than fanned out — failing closed
134
+ * on submission would turn away brand-new employers, who are exactly the ones with
135
+ * no membership yet. Assigning them a group is what releases it. */
136
+ export const employerNeedsTriage = (
137
+ employer: EmployerGroupInput|undefined,
138
+ hubId: string,
139
+ hub: Pick<InstituteData, "groupSettings">|undefined
140
+ ): boolean =>
141
+ getSharingScope(hub) === "membership" && getEmployerGroupIds(employer, hubId).length === 0;
142
+
143
+ /**
144
+ * Where an employer's offer actually lands: their intent, narrowed by membership
145
+ * when the hub has asked for that, and always narrowed to approved schools.
146
+ */
147
+ export const resolveEmployerSchools = (
148
+ employer: EmployerGroupInput|undefined,
149
+ hubId: string,
150
+ hub: Pick<InstituteData, "groupSettings">|undefined,
151
+ schools: {[id: string]: SchoolGroupInput}
152
+ ): ResolvedEmployerReach => {
153
+ const scope = getSharingScope(hub);
154
+ const approved = approvedHubSchools(schools, hubId);
155
+ const sharing = getEmployerSharing(employer, hubId);
156
+
157
+ const intended = sharing.mode === "all" ? approved : uniq([
158
+ ...schoolsInGroups(sharing.groups ?? [], hubId, schools),
159
+ ...(sharing.specificSchools ?? []),
160
+ ]).filter((id) => approved.includes(id));
161
+
162
+ const permitted = permittedSchools(employer, hubId, hub, schools);
163
+ const resolved = intended.filter((id) => permitted.includes(id));
164
+
165
+ const membership = getEmployerGroupIds(employer, hubId);
166
+ const conflicts: EmployerReachConflict[] = [];
167
+
168
+ // Reported whatever the scope, because it's a fact about the employer's record
169
+ // rather than about the clamp: the hub filed them under a region they never
170
+ // agreed to work with, and will want to know before the setting is switched on.
171
+ if (sharing.mode === "custom" && membership.some((g) => !(sharing.groups ?? []).includes(g))) {
172
+ conflicts.push("membershipOutsideConsent");
173
+ }
174
+ if (intended.length > 0 && resolved.length === 0) {
175
+ conflicts.push("emptyReach");
176
+ }
177
+
178
+ return {schools: resolved, intended, clamped: resolved.length < intended.length, conflicts, scope};
179
+ };
180
+
181
+ /** Both sides of a group, for management screens and pickers. */
182
+ export const resolveGroupMembers = (
183
+ groupId: string,
184
+ hubId: string,
185
+ members: {
186
+ schools?: {[id: string]: SchoolGroupInput},
187
+ employers?: {[id: string]: EmployerGroupInput},
188
+ }
189
+ ): {schools: string[], employers: string[]} => ({
190
+ schools: Object.entries(members.schools || {})
191
+ .filter(([, s]) => getSchoolGroupIds(s, hubId).includes(groupId))
192
+ .map(([id]) => id),
193
+ employers: Object.entries(members.employers || {})
194
+ .filter(([, e]) => getEmployerGroupIds(e, hubId).includes(groupId))
195
+ .map(([id]) => id),
196
+ });
197
+
198
+ /** Groups offered to a given member type. Absent `appliesTo` means schools only —
199
+ * every group created before employers had membership. */
200
+ export const groupsFor = (
201
+ groups: {[id: string]: HubGroup},
202
+ memberType: "school"|"employer"
203
+ ): {[id: string]: HubGroup} =>
204
+ Object.fromEntries(Object.entries(groups || {})
205
+ .filter(([, g]) => (g.appliesTo ?? ["school"]).includes(memberType)));
206
+
207
+ /** Of the groups an employer picked to work with, the ones that also make them a
208
+ * member. Picking "North" as somewhere you want to work is a statement that you
209
+ * belong there, so the hub doesn't have to file them by hand afterwards — but only
210
+ * for groups the hub marked as applying to employers. */
211
+ export const groupsGrantingMembership = (
212
+ selectedGroupIds: string[],
213
+ groups: {[id: string]: HubGroup}
214
+ ): string[] =>
215
+ selectedGroupIds.filter((id) => (groups?.[id]?.appliesTo ?? ["school"]).includes("employer"));
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./surveys/registry";
14
14
  export * from "./surveys/schedule";
15
15
  export * from "./skillsResolver";
16
16
  export * from "./productResolver";
17
+ export * from "./groups";
17
18
  export * from "./emailSections";
18
19
  export * from "./exportTransformers";
19
20
  export * from "./compassExport";
@@ -830,10 +830,17 @@ export type ProviderContactData = {
830
830
  providerConsentDate?: string,
831
831
  MATschools?: string[],
832
832
  notes?: Descendant[],
833
+ /** @deprecated The employer's sharing intent, migrated to `sharing`. Kept so
834
+ * anything not yet migrated still resolves — read it via `getEmployerSharing`,
835
+ * never directly. */
833
836
  schoolGroups?: {
834
837
  groups?: string[],
835
838
  specificSchools?: string[],
836
839
  },
840
+ /** Hub groups this employer belongs to. Written by the hub only. */
841
+ groups?: string[],
842
+ /** Who the employer wants to work with. Written by the employer only. */
843
+ sharing?: EmployerSharing,
837
844
  additionalData?: {[key: string]: unknown},
838
845
  status: "uploaded"|"approved"|"rejected"|"providerReviewed"|"blocked"}},
839
846
  }&Address
@@ -884,7 +891,10 @@ export type InstituteData = {
884
891
  exists: boolean,
885
892
  invited: string,
886
893
  status: "invited"|"approved"|"declined",
894
+ /** @deprecated Migrated to `groups`. Read via `getSchoolGroupIds`. */
887
895
  schoolGroups?: string[],
896
+ /** Hub groups this school belongs to. */
897
+ groups?: string[],
888
898
  notes?: Descendant[],
889
899
  emailsSent?: {
890
900
  sent?: Timestamp,
@@ -908,6 +918,13 @@ export type InstituteData = {
908
918
  connectionToken: string,
909
919
  fields?: string[]
910
920
  },
921
+ /** Careers hub policy for group membership. `employerSharingScope: "membership"`
922
+ * narrows what an employer reaches to the schools in the employer's own groups,
923
+ * without editing what the employer asked for — drop back to "unrestricted" and
924
+ * their original preference takes effect again. */
925
+ groupSettings?: {
926
+ employerSharingScope: "membership"|"unrestricted",
927
+ },
911
928
  emailDomain: string,
912
929
  splitBilling?: boolean,
913
930
  adminBillingContactId?: string,
@@ -1659,7 +1676,9 @@ export type SchoolData = OrganisationAddress&{
1659
1676
  exists: boolean,
1660
1677
  invited: string,
1661
1678
  status: "invited"|"approved"|"declined",
1679
+ /** @deprecated Migrated to `groups`. Read via `getSchoolGroupIds`. */
1662
1680
  schoolGroups?: string[],
1681
+ groups?: string[],
1663
1682
  emailsSent?: {
1664
1683
  sent?: Timestamp,
1665
1684
  log: {
@@ -1671,10 +1690,31 @@ export type SchoolData = OrganisationAddress&{
1671
1690
  }},
1672
1691
  }
1673
1692
 
1674
- // SchoolGroup is a group that schools can be assigned to by a Careers Hub
1675
- export type SchoolGroup = {
1693
+ /** A group a Careers Hub can assign both schools and employers to a region,
1694
+ * most often. Stored in the `hubGroups` collection (migrated from `schoolGroups`,
1695
+ * keeping the same document IDs so every existing membership array still resolves). */
1696
+ export type HubGroup = {
1676
1697
  name: string,
1677
1698
  careersHubId: string,
1699
+ /** Which member types this group can be assigned to. Absent means schools only,
1700
+ * which is what every group created before employers had membership was. */
1701
+ appliesTo?: ("school"|"employer")[],
1702
+ /** Regions are usually exclusive — a member belongs to one. Enforced in the UI
1703
+ * as single-select; the data stays an array either way. */
1704
+ exclusive?: boolean,
1705
+ }
1706
+
1707
+ /** @deprecated Renamed to HubGroup now that employers are members too. */
1708
+ export type SchoolGroup = HubGroup;
1709
+
1710
+ /** Who an employer told a hub they want to work with. Written by the employer, and
1711
+ * never overwritten by the hub — the hub expresses its policy through group
1712
+ * membership plus `InstituteData.groupSettings`, which narrows this at resolve time.
1713
+ * See `resolveEmployerSchools`. */
1714
+ export type EmployerSharing = {
1715
+ mode: "all"|"custom",
1716
+ groups?: string[],
1717
+ specificSchools?: string[],
1678
1718
  }
1679
1719
 
1680
1720
  export type ExternalEvent = {
@@ -1862,6 +1902,16 @@ export type ExternalEventRequest = {
1862
1902
  schoolSelectionType?: "allSchools"|"selectGroups"|"specificSchools",
1863
1903
  schools?: string[],
1864
1904
  schoolGroups?: string[],
1905
+ /** The schools this request actually reached, frozen at dispatch. Resolution is
1906
+ * live everywhere else, so without this a hub that later widens its scoping would
1907
+ * have no record of who was reached under the old policy — and nothing stops a
1908
+ * historical offer being silently re-fanned-out. */
1909
+ resolvedSchools?: string[],
1910
+ resolvedAt?: string,
1911
+ resolvedUnderScope?: "membership"|"unrestricted",
1912
+ /** Set when membership narrowed the employer's stated preference, so the hub can
1913
+ * see the offer was wider than what went out. */
1914
+ resolvedClamped?: boolean,
1865
1915
  numberSharedWith?: number,
1866
1916
  maxSchools?: number,
1867
1917
  viewedBy?: {[key: string]: boolean},
@@ -2722,7 +2772,10 @@ export type CareersHubInvite = {
2722
2772
  schoolName: string,
2723
2773
  invited: string,
2724
2774
  status: "invited"|"approved"|"declined",
2775
+ /** @deprecated Migrated to `groups`, and carried onto the school's
2776
+ * careersHubLinks entry on registration. */
2725
2777
  schoolGroups?: string[],
2778
+ groups?: string[],
2726
2779
  emailsSent?: {
2727
2780
  sent?: Timestamp,
2728
2781
  log: {
@@ -2741,7 +2794,9 @@ export type TrustInvite = {
2741
2794
  schoolName: string,
2742
2795
  invited: string,
2743
2796
  status: "invited"|"approved"|"declined",
2797
+ /** @deprecated Migrated to `groups`. */
2744
2798
  schoolGroups?: string[],
2799
+ groups?: string[],
2745
2800
  emailsSent?: {
2746
2801
  sent?: Timestamp,
2747
2802
  log: {