placementt-core 1.400.1251 → 1.400.1253

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.
@@ -12,6 +12,23 @@ export type BulkEngagementFlag = "noContacts" | "noRenewalDate" | "noQuote" | "n
12
12
  export declare const BULK_ENGAGEMENT_FLAG_LABELS: Record<BulkEngagementFlag, string>;
13
13
  /** Flags that stop a school being sent the email at all. */
14
14
  export declare const BULK_ENGAGEMENT_BLOCKING_FLAGS: BulkEngagementFlag[];
15
+ /** The account types the send popup filters by, and what it calls them. */
16
+ export declare const BULK_ENGAGEMENT_PACKAGE_LABELS: {
17
+ [pkg: string]: string;
18
+ };
19
+ /** The products the send popup filters by. Flags on ResolvedProducts. */
20
+ export type BulkEngagementProduct = "wex" | "employerEvents" | "destinations";
21
+ export declare const BULK_ENGAGEMENT_PRODUCTS: BulkEngagementProduct[];
22
+ export declare const BULK_ENGAGEMENT_PRODUCT_LABELS: Record<BulkEngagementProduct, string>;
23
+ /** What the admin has ticked in the send popup's filters. Empty means any. */
24
+ export type BulkEngagementFilters = {
25
+ packages: string[];
26
+ products: string[];
27
+ };
28
+ /** Who the popup's "Send test" goes to. Fixed on the server, never taken from the request. */
29
+ export declare const BULK_TEST_RECIPIENT = "tom@careerthread.co.uk";
30
+ /** How many schools' copies one test sends. Matches the cap in the callable's contract. */
31
+ export declare const BULK_TEST_SCHOOLS = 3;
15
32
  /** A school that had this email this recently isn't suggested it again. */
16
33
  export declare const RECENTLY_SENT_DAYS = 60;
17
34
  export type BulkEngagementSchool = {
@@ -46,3 +63,16 @@ export type BulkEngagementSuggestion = {
46
63
  * @return {BulkEngagementSuggestion} whether to suggest it, why, and its flags.
47
64
  */
48
65
  export declare const bulkEngagementSuggestion: (templateKey: string, school: BulkEngagementSchool) => BulkEngagementSuggestion;
66
+ /**
67
+ * Whether a school passes the send popup's filters: its package is one of
68
+ * those ticked, and it has any of the products ticked. An empty filter
69
+ * matches everything.
70
+ *
71
+ * @param {object} school the school's package and products.
72
+ * @param {BulkEngagementFilters} filters what is ticked.
73
+ * @return {boolean} whether the school matches.
74
+ */
75
+ export declare const matchesBulkFilters: (school: {
76
+ package: string;
77
+ products: string[];
78
+ }, { packages, products }: BulkEngagementFilters) => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bulkEngagementSuggestion = exports.RECENTLY_SENT_DAYS = exports.BULK_ENGAGEMENT_BLOCKING_FLAGS = exports.BULK_ENGAGEMENT_FLAG_LABELS = void 0;
3
+ exports.matchesBulkFilters = exports.bulkEngagementSuggestion = exports.RECENTLY_SENT_DAYS = exports.BULK_TEST_SCHOOLS = exports.BULK_TEST_RECIPIENT = exports.BULK_ENGAGEMENT_PRODUCT_LABELS = exports.BULK_ENGAGEMENT_PRODUCTS = exports.BULK_ENGAGEMENT_PACKAGE_LABELS = exports.BULK_ENGAGEMENT_BLOCKING_FLAGS = exports.BULK_ENGAGEMENT_FLAG_LABELS = void 0;
4
4
  const renewals_1 = require("./renewals");
5
5
  const constants_1 = require("./constants");
6
6
  exports.BULK_ENGAGEMENT_FLAG_LABELS = {
@@ -12,6 +12,23 @@ exports.BULK_ENGAGEMENT_FLAG_LABELS = {
12
12
  };
13
13
  /** Flags that stop a school being sent the email at all. */
14
14
  exports.BULK_ENGAGEMENT_BLOCKING_FLAGS = ["noContacts"];
15
+ /** The account types the send popup filters by, and what it calls them. */
16
+ exports.BULK_ENGAGEMENT_PACKAGE_LABELS = {
17
+ "institutes-one": "School",
18
+ "institutes-two": "Trust",
19
+ "careersHub": "Careers hub",
20
+ "careersSchool": "Hub school",
21
+ };
22
+ exports.BULK_ENGAGEMENT_PRODUCTS = ["wex", "employerEvents", "destinations"];
23
+ exports.BULK_ENGAGEMENT_PRODUCT_LABELS = {
24
+ wex: "Work experience",
25
+ employerEvents: "Employer events",
26
+ destinations: "Destinations",
27
+ };
28
+ /** Who the popup's "Send test" goes to. Fixed on the server, never taken from the request. */
29
+ exports.BULK_TEST_RECIPIENT = "tom@careerthread.co.uk";
30
+ /** How many schools' copies one test sends. Matches the cap in the callable's contract. */
31
+ exports.BULK_TEST_SCHOOLS = 3;
15
32
  /** A school that had this email this recently isn't suggested it again. */
16
33
  exports.RECENTLY_SENT_DAYS = 60;
17
34
  /**
@@ -69,4 +86,16 @@ const bulkEngagementSuggestion = (templateKey, school) => {
69
86
  return { suggested: true, reason: `Renews in ${days} days`, flags };
70
87
  };
71
88
  exports.bulkEngagementSuggestion = bulkEngagementSuggestion;
89
+ /**
90
+ * Whether a school passes the send popup's filters: its package is one of
91
+ * those ticked, and it has any of the products ticked. An empty filter
92
+ * matches everything.
93
+ *
94
+ * @param {object} school the school's package and products.
95
+ * @param {BulkEngagementFilters} filters what is ticked.
96
+ * @return {boolean} whether the school matches.
97
+ */
98
+ const matchesBulkFilters = (school, { packages, products }) => (!packages.length || packages.includes(school.package)) &&
99
+ (!products.length || products.some((p) => school.products.includes(p)));
100
+ exports.matchesBulkFilters = matchesBulkFilters;
72
101
  //# sourceMappingURL=bulkEngagement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bulkEngagement.js","sourceRoot":"","sources":["../src/bulkEngagement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bulkEngagement.js","sourceRoot":"","sources":["../src/bulkEngagement.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ jest.mock("./firebase/firebaseQuery", () => ({ __esModule: true, default: class
5
5
  } }));
6
6
  const productResolver_1 = require("./productResolver");
7
7
  const bulkEngagement_1 = require("./bulkEngagement");
8
+ const engagement_1 = require("./callables/engagement");
8
9
  const school = (renewalDate, overrides = {}) => ({
9
10
  name: "Calder Park Academy",
10
11
  package: "institutes-one",
@@ -60,4 +61,59 @@ describe("bulk engagement suggestions", () => {
60
61
  expect(suggest("engagementPickFeatures", school(), "2026-11-04", { nextOnboardingTemplate: "engagementPlanYear" }).suggested).toBe(false);
61
62
  });
62
63
  });
64
+ describe("matchesBulkFilters", () => {
65
+ const trust = { package: "institutes-two", products: ["wex", "destinations"] };
66
+ const hub = { package: "careersHub", products: ["employerEvents"] };
67
+ const none = { package: "institutes-one", products: [] };
68
+ it("matches everything when nothing is ticked", () => {
69
+ [trust, hub, none].forEach((s) => expect((0, bulkEngagement_1.matchesBulkFilters)(s, { packages: [], products: [] })).toBe(true));
70
+ });
71
+ it("matches a package that is one of those ticked", () => {
72
+ const packages = ["institutes-two", "careersHub"];
73
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages, products: [] })).toBe(true);
74
+ expect((0, bulkEngagement_1.matchesBulkFilters)(hub, { packages, products: [] })).toBe(true);
75
+ expect((0, bulkEngagement_1.matchesBulkFilters)(none, { packages, products: [] })).toBe(false);
76
+ });
77
+ it("matches a school with any of the products ticked, not all of them", () => {
78
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages: [], products: ["destinations", "employerEvents"] })).toBe(true);
79
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages: [], products: ["employerEvents"] })).toBe(false);
80
+ });
81
+ it("never matches a school with no products once a product is ticked", () => {
82
+ expect((0, bulkEngagement_1.matchesBulkFilters)(none, { packages: [], products: ["wex"] })).toBe(false);
83
+ });
84
+ it("needs both filters to pass", () => {
85
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages: ["institutes-two"], products: ["wex"] })).toBe(true);
86
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages: ["careersHub"], products: ["wex"] })).toBe(false);
87
+ expect((0, bulkEngagement_1.matchesBulkFilters)(trust, { packages: ["institutes-two"], products: ["employerEvents"] })).toBe(false);
88
+ });
89
+ it("labels every package and product in sentence case", () => {
90
+ expect(bulkEngagement_1.BULK_ENGAGEMENT_PACKAGE_LABELS).toEqual({
91
+ "institutes-one": "School",
92
+ "institutes-two": "Trust",
93
+ "careersHub": "Careers hub",
94
+ "careersSchool": "Hub school",
95
+ });
96
+ expect(bulkEngagement_1.BULK_ENGAGEMENT_PRODUCTS.map((p) => bulkEngagement_1.BULK_ENGAGEMENT_PRODUCT_LABELS[p])).toEqual(["Work experience", "Employer events", "Destinations"]);
97
+ });
98
+ it("offers products that resolveProducts sets", () => {
99
+ const products = (0, productResolver_1.resolveProducts)({ package: "careersHub", workExperience: true });
100
+ expect(bulkEngagement_1.BULK_ENGAGEMENT_PRODUCTS.filter((p) => products[p])).toEqual(["employerEvents"]);
101
+ });
102
+ });
103
+ describe("sendBulkEngagementTest contract", () => {
104
+ const request = (count) => ({
105
+ templateKey: "engagementRenewalDue",
106
+ oIds: Array.from({ length: count }, (_, i) => `school-${i}`),
107
+ subject: "Renewing",
108
+ body: [{ type: "paragraph" }],
109
+ });
110
+ const contract = engagement_1.engagementCallables["bulkEngagement-sendBulkEngagementTest"].request;
111
+ it("takes up to BULK_TEST_SCHOOLS schools and no more", () => {
112
+ expect(contract.safeParse(request(bulkEngagement_1.BULK_TEST_SCHOOLS)).success).toBe(true);
113
+ expect(contract.safeParse(request(bulkEngagement_1.BULK_TEST_SCHOOLS + 1)).success).toBe(false);
114
+ });
115
+ it("has no way to name a recipient", () => {
116
+ expect(contract.parse({ ...request(1), to: "someone@school.sch.uk" })).not.toHaveProperty("to");
117
+ });
118
+ });
63
119
  //# sourceMappingURL=bulkEngagement.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bulkEngagement.test.js","sourceRoot":"","sources":["../src/bulkEngagement.test.ts"],"names":[],"mappings":";;AAAA,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,EAAC,CAAC,CAAC,CAAC;AAC5D,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC,EAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE;KAAQ,EAAC,CAAC,CAAC,CAAC;AAGrF,uDAAkD;AAClD,qDAA0D;AAE1D,MAAM,MAAM,GAAG,CAAC,WAAoB,EAAE,YAAoC,EAAE,EAAiB,EAAE,CAAC,CAAC;IAC7F,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,gBAAgB;IACzB,cAAc,EAAE,IAAI;IACpB,EAAE,EAAE,EAAC,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAC,WAAW,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAC;IAC7G,GAAG,SAAS;CACc,CAAA,CAAC;AAE/B,MAAM,OAAO,GAAG,CAAC,WAAmB,EAAE,SAAwB,EAAE,IAAY,EAAE,QAAyG,EAAE,EAAE,EAAE,CACzL,IAAA,yCAAwB,EAAC,WAAW,EAAE;IAClC,SAAS;IACT,QAAQ,EAAE,IAAA,iCAAe,EAAC,SAAS,CAAC;IACpC,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG,IAAI,YAAY,CAAC;IAClC,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;IAChC,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;IACpD,QAAQ,EAAE,KAAK,CAAC,QAAQ;CAC3B,CAAC,CAAC;AAEP,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,EAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAC,CAAC,CAAC;QAC1I,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClG,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,OAAO,CAAC,0BAA0B,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrG,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnG,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;QAC5F,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxF,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpG,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,EAAE,EAAC,OAAO,EAAE,eAAe,EAAC,CAAC,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACnE,MAAM,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,EAAE,EAAC,QAAQ,EAAE,sBAAsB,EAAC,CAAC,CAAC;QACvH,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,cAAc,CAAC,CAAC,EAAC,CAAC,CAAC;QAClG,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,EAAE,EAAC,QAAQ,EAAE,sBAAsB,EAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC,CAAC,KAAK,CAAC;aACnF,OAAO,CAAC,CAAC,eAAe,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,EAAE,EAAC,cAAc,EAAE,EAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAC,EAA2B,CAAC,CAAC;QACjI,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAC,YAAY,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAC,CAAC,CAAC;IACnJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAC,sBAAsB,EAAE,wBAAwB,EAAC,CAAC,CAAC;aAChH,aAAa,CAAC,EAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,4BAA4B,EAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAC,sBAAsB,EAAE,oBAAoB,EAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5I,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bulkEngagement.test.js","sourceRoot":"","sources":["../src/bulkEngagement.test.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,8 @@ export declare const engagementCallables: {
14
14
  oId: z.ZodString;
15
15
  name: z.ZodString;
16
16
  package: z.ZodString;
17
+ /** The products the admin can filter this school by. */
18
+ products: z.ZodArray<z.ZodEnum<["wex", "employerEvents", "destinations"]>, "many">;
17
19
  suggested: z.ZodBoolean;
18
20
  reason: z.ZodOptional<z.ZodString>;
19
21
  flags: z.ZodArray<z.ZodEnum<["noContacts", "noRenewalDate", "noQuote", "noFinanceContact", "sentRecently"]>, "many">;
@@ -30,6 +32,7 @@ export declare const engagementCallables: {
30
32
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
31
33
  contacts: number;
32
34
  params: Record<string, string>;
35
+ products: ("employerEvents" | "wex" | "destinations")[];
33
36
  suggested: boolean;
34
37
  reason?: string | undefined;
35
38
  lastSent?: string | undefined;
@@ -40,6 +43,7 @@ export declare const engagementCallables: {
40
43
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
41
44
  contacts: number;
42
45
  params: Record<string, string>;
46
+ products: ("employerEvents" | "wex" | "destinations")[];
43
47
  suggested: boolean;
44
48
  reason?: string | undefined;
45
49
  lastSent?: string | undefined;
@@ -52,6 +56,7 @@ export declare const engagementCallables: {
52
56
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
53
57
  contacts: number;
54
58
  params: Record<string, string>;
59
+ products: ("employerEvents" | "wex" | "destinations")[];
55
60
  suggested: boolean;
56
61
  reason?: string | undefined;
57
62
  lastSent?: string | undefined;
@@ -64,6 +69,7 @@ export declare const engagementCallables: {
64
69
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
65
70
  contacts: number;
66
71
  params: Record<string, string>;
72
+ products: ("employerEvents" | "wex" | "destinations")[];
67
73
  suggested: boolean;
68
74
  reason?: string | undefined;
69
75
  lastSent?: string | undefined;
@@ -120,6 +126,54 @@ export declare const engagementCallables: {
120
126
  }>;
121
127
  }>;
122
128
  };
129
+ /**
130
+ * Sends each school's copy of the email to CareerThread's test address, so
131
+ * it can be read before the real send. Nothing is logged on the school or
132
+ * changed on it, and no follow-ups start. The address is set on the server.
133
+ */
134
+ "bulkEngagement-sendBulkEngagementTest": {
135
+ request: z.ZodObject<{
136
+ templateKey: z.ZodString;
137
+ oIds: z.ZodArray<z.ZodString, "many">;
138
+ subject: z.ZodString;
139
+ body: z.ZodArray<z.ZodUnknown, "many">;
140
+ heroImage: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
141
+ }, "strip", z.ZodTypeAny, {
142
+ body: unknown[];
143
+ subject: string;
144
+ templateKey: string;
145
+ oIds: string[];
146
+ heroImage?: string | undefined;
147
+ }, {
148
+ body: unknown[];
149
+ subject: string;
150
+ templateKey: string;
151
+ oIds: string[];
152
+ heroImage?: string | null | undefined;
153
+ }>;
154
+ response: z.ZodObject<{
155
+ results: z.ZodRecord<z.ZodString, z.ZodObject<{
156
+ sent: z.ZodArray<z.ZodString, "many">;
157
+ error: z.ZodOptional<z.ZodString>;
158
+ }, "strip", z.ZodTypeAny, {
159
+ sent: string[];
160
+ error?: string | undefined;
161
+ }, {
162
+ sent: string[];
163
+ error?: string | undefined;
164
+ }>>;
165
+ }, "strip", z.ZodTypeAny, {
166
+ results: Record<string, {
167
+ sent: string[];
168
+ error?: string | undefined;
169
+ }>;
170
+ }, {
171
+ results: Record<string, {
172
+ sent: string[];
173
+ error?: string | undefined;
174
+ }>;
175
+ }>;
176
+ };
123
177
  /** One-off: removes the open renewal email tasks the old automatic schedule made. */
124
178
  "bulkEngagement-clearRenewalEmailTasks": {
125
179
  request: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
@@ -12,6 +12,7 @@ const types_1 = require("./types");
12
12
  * an email interaction on the school. All of them are admin-only.
13
13
  */
14
14
  const flag = zod_1.z.enum(["noContacts", "noRenewalDate", "noQuote", "noFinanceContact", "sentRecently"]);
15
+ const product = zod_1.z.enum(["wex", "employerEvents", "destinations"]);
15
16
  exports.engagementCallables = {
16
17
  "bulkEngagement-getBulkEngagementSchools": {
17
18
  request: zod_1.z.object({
@@ -23,6 +24,8 @@ exports.engagementCallables = {
23
24
  oId: zod_1.z.string(),
24
25
  name: zod_1.z.string(),
25
26
  package: zod_1.z.string(),
27
+ /** The products the admin can filter this school by. */
28
+ products: zod_1.z.array(product),
26
29
  suggested: zod_1.z.boolean(),
27
30
  reason: zod_1.z.string().optional(),
28
31
  flags: zod_1.z.array(flag),
@@ -52,6 +55,23 @@ exports.engagementCallables = {
52
55
  results: zod_1.z.record(zod_1.z.string(), zod_1.z.object({ sent: zod_1.z.array(zod_1.z.string()), error: zod_1.z.string().optional() })),
53
56
  }),
54
57
  },
58
+ /**
59
+ * Sends each school's copy of the email to CareerThread's test address, so
60
+ * it can be read before the real send. Nothing is logged on the school or
61
+ * changed on it, and no follow-ups start. The address is set on the server.
62
+ */
63
+ "bulkEngagement-sendBulkEngagementTest": {
64
+ request: zod_1.z.object({
65
+ templateKey: zod_1.z.string().min(1),
66
+ oIds: zod_1.z.array(zod_1.z.string().min(1)).min(1, "Pick at least one school.").max(3),
67
+ subject: zod_1.z.string().trim().min(1, "Give it a subject."),
68
+ body: zod_1.z.array(zod_1.z.unknown()).min(1),
69
+ heroImage: (0, types_1.optionalField)(zod_1.z.string()),
70
+ }),
71
+ response: zod_1.z.object({
72
+ results: zod_1.z.record(zod_1.z.string(), zod_1.z.object({ sent: zod_1.z.array(zod_1.z.string()), error: zod_1.z.string().optional() })),
73
+ }),
74
+ },
55
75
  /** One-off: removes the open renewal email tasks the old automatic schedule made. */
56
76
  "bulkEngagement-clearRenewalEmailTasks": {
57
77
  request: zod_1.z.object({}).optional(),
@@ -1 +1 @@
1
- {"version":3,"file":"engagement.js","sourceRoot":"","sources":["../../src/callables/engagement.ts"],"names":[],"mappings":";;;AAAA,6BAAsB;AACtB,mCAAqD;AAErD;;;;;;;GAOG;AAEH,MAAM,IAAI,GAAG,OAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,kBAAkB,EAAE,cAAc,CAAC,CAAC,CAAC;AAEvF,QAAA,mBAAmB,GAAG;IAC/B,yCAAyC,EAAE;QACvC,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC;YACd,mEAAmE;YACnE,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;SACjC,CAAC;QACF,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,CAAC;gBACtB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE;gBACf,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;gBAChB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;gBACnB,SAAS,EAAE,OAAC,CAAC,OAAO,EAAE;gBACtB,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBAC7B,KAAK,EAAE,OAAC,CAAC,KAAK,CAAC,IAAI,CAAC;gBACpB,wDAAwD;gBACxD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;gBACpB,8DAA8D;gBAC9D,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBAC/B,sEAAsE;gBACtE,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC;aAC3C,CAAC,CAAC;SACN,CAAC;KACL;IACD,wCAAwC,EAAE;QACtC,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC;YACd,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;YAC7E,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC;YACvD,8EAA8E;YAC9E,IAAI,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACjC,4DAA4D;YAC5D,SAAS,EAAE,IAAA,qBAAa,EAAC,OAAC,CAAC,MAAM,EAAE,CAAC;YACpC,oFAAoF;YACpF,SAAS,EAAE,OAAC,CAAC,OAAO,EAAE;SACzB,CAAC;QACF,+DAA+D;QAC/D,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,CAAC,EAAC,IAAI,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAC,CAAC,CAAC;SACrG,CAAC;KACL;IACD,qFAAqF;IACrF,uCAAuC,EAAE;QACrC,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;QAChC,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC,EAAC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,EAAC,CAAC;KAC5C;CACoB,CAAC"}
1
+ {"version":3,"file":"engagement.js","sourceRoot":"","sources":["../../src/callables/engagement.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ export declare const allCallables: {
24
24
  oId: z.ZodString;
25
25
  name: z.ZodString;
26
26
  package: z.ZodString;
27
+ products: z.ZodArray<z.ZodEnum<["wex", "employerEvents", "destinations"]>, "many">;
27
28
  suggested: z.ZodBoolean;
28
29
  reason: z.ZodOptional<z.ZodString>;
29
30
  flags: z.ZodArray<z.ZodEnum<["noContacts", "noRenewalDate", "noQuote", "noFinanceContact", "sentRecently"]>, "many">;
@@ -37,6 +38,7 @@ export declare const allCallables: {
37
38
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
38
39
  contacts: number;
39
40
  params: Record<string, string>;
41
+ products: ("employerEvents" | "wex" | "destinations")[];
40
42
  suggested: boolean;
41
43
  reason?: string | undefined;
42
44
  lastSent?: string | undefined;
@@ -47,6 +49,7 @@ export declare const allCallables: {
47
49
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
48
50
  contacts: number;
49
51
  params: Record<string, string>;
52
+ products: ("employerEvents" | "wex" | "destinations")[];
50
53
  suggested: boolean;
51
54
  reason?: string | undefined;
52
55
  lastSent?: string | undefined;
@@ -59,6 +62,7 @@ export declare const allCallables: {
59
62
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
60
63
  contacts: number;
61
64
  params: Record<string, string>;
65
+ products: ("employerEvents" | "wex" | "destinations")[];
62
66
  suggested: boolean;
63
67
  reason?: string | undefined;
64
68
  lastSent?: string | undefined;
@@ -71,6 +75,7 @@ export declare const allCallables: {
71
75
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
72
76
  contacts: number;
73
77
  params: Record<string, string>;
78
+ products: ("employerEvents" | "wex" | "destinations")[];
74
79
  suggested: boolean;
75
80
  reason?: string | undefined;
76
81
  lastSent?: string | undefined;
@@ -123,6 +128,49 @@ export declare const allCallables: {
123
128
  }>;
124
129
  }>;
125
130
  };
131
+ "bulkEngagement-sendBulkEngagementTest": {
132
+ request: z.ZodObject<{
133
+ templateKey: z.ZodString;
134
+ oIds: z.ZodArray<z.ZodString, "many">;
135
+ subject: z.ZodString;
136
+ body: z.ZodArray<z.ZodUnknown, "many">;
137
+ heroImage: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
138
+ }, "strip", z.ZodTypeAny, {
139
+ body: unknown[];
140
+ subject: string;
141
+ templateKey: string;
142
+ oIds: string[];
143
+ heroImage?: string | undefined;
144
+ }, {
145
+ body: unknown[];
146
+ subject: string;
147
+ templateKey: string;
148
+ oIds: string[];
149
+ heroImage?: string | null | undefined;
150
+ }>;
151
+ response: z.ZodObject<{
152
+ results: z.ZodRecord<z.ZodString, z.ZodObject<{
153
+ sent: z.ZodArray<z.ZodString, "many">;
154
+ error: z.ZodOptional<z.ZodString>;
155
+ }, "strip", z.ZodTypeAny, {
156
+ sent: string[];
157
+ error?: string | undefined;
158
+ }, {
159
+ sent: string[];
160
+ error?: string | undefined;
161
+ }>>;
162
+ }, "strip", z.ZodTypeAny, {
163
+ results: Record<string, {
164
+ sent: string[];
165
+ error?: string | undefined;
166
+ }>;
167
+ }, {
168
+ results: Record<string, {
169
+ sent: string[];
170
+ error?: string | undefined;
171
+ }>;
172
+ }>;
173
+ };
126
174
  "bulkEngagement-clearRenewalEmailTasks": {
127
175
  request: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
128
176
  response: z.ZodObject<{
@@ -7999,6 +8047,7 @@ export declare const callableGroups: {
7999
8047
  oId: z.ZodString;
8000
8048
  name: z.ZodString;
8001
8049
  package: z.ZodString;
8050
+ products: z.ZodArray<z.ZodEnum<["wex", "employerEvents", "destinations"]>, "many">;
8002
8051
  suggested: z.ZodBoolean;
8003
8052
  reason: z.ZodOptional<z.ZodString>;
8004
8053
  flags: z.ZodArray<z.ZodEnum<["noContacts", "noRenewalDate", "noQuote", "noFinanceContact", "sentRecently"]>, "many">;
@@ -8012,6 +8061,7 @@ export declare const callableGroups: {
8012
8061
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
8013
8062
  contacts: number;
8014
8063
  params: Record<string, string>;
8064
+ products: ("employerEvents" | "wex" | "destinations")[];
8015
8065
  suggested: boolean;
8016
8066
  reason?: string | undefined;
8017
8067
  lastSent?: string | undefined;
@@ -8022,6 +8072,7 @@ export declare const callableGroups: {
8022
8072
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
8023
8073
  contacts: number;
8024
8074
  params: Record<string, string>;
8075
+ products: ("employerEvents" | "wex" | "destinations")[];
8025
8076
  suggested: boolean;
8026
8077
  reason?: string | undefined;
8027
8078
  lastSent?: string | undefined;
@@ -8034,6 +8085,7 @@ export declare const callableGroups: {
8034
8085
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
8035
8086
  contacts: number;
8036
8087
  params: Record<string, string>;
8088
+ products: ("employerEvents" | "wex" | "destinations")[];
8037
8089
  suggested: boolean;
8038
8090
  reason?: string | undefined;
8039
8091
  lastSent?: string | undefined;
@@ -8046,6 +8098,7 @@ export declare const callableGroups: {
8046
8098
  flags: ("noContacts" | "noRenewalDate" | "noQuote" | "noFinanceContact" | "sentRecently")[];
8047
8099
  contacts: number;
8048
8100
  params: Record<string, string>;
8101
+ products: ("employerEvents" | "wex" | "destinations")[];
8049
8102
  suggested: boolean;
8050
8103
  reason?: string | undefined;
8051
8104
  lastSent?: string | undefined;
@@ -8098,6 +8151,49 @@ export declare const callableGroups: {
8098
8151
  }>;
8099
8152
  }>;
8100
8153
  };
8154
+ "bulkEngagement-sendBulkEngagementTest": {
8155
+ request: z.ZodObject<{
8156
+ templateKey: z.ZodString;
8157
+ oIds: z.ZodArray<z.ZodString, "many">;
8158
+ subject: z.ZodString;
8159
+ body: z.ZodArray<z.ZodUnknown, "many">;
8160
+ heroImage: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
8161
+ }, "strip", z.ZodTypeAny, {
8162
+ body: unknown[];
8163
+ subject: string;
8164
+ templateKey: string;
8165
+ oIds: string[];
8166
+ heroImage?: string | undefined;
8167
+ }, {
8168
+ body: unknown[];
8169
+ subject: string;
8170
+ templateKey: string;
8171
+ oIds: string[];
8172
+ heroImage?: string | null | undefined;
8173
+ }>;
8174
+ response: z.ZodObject<{
8175
+ results: z.ZodRecord<z.ZodString, z.ZodObject<{
8176
+ sent: z.ZodArray<z.ZodString, "many">;
8177
+ error: z.ZodOptional<z.ZodString>;
8178
+ }, "strip", z.ZodTypeAny, {
8179
+ sent: string[];
8180
+ error?: string | undefined;
8181
+ }, {
8182
+ sent: string[];
8183
+ error?: string | undefined;
8184
+ }>>;
8185
+ }, "strip", z.ZodTypeAny, {
8186
+ results: Record<string, {
8187
+ sent: string[];
8188
+ error?: string | undefined;
8189
+ }>;
8190
+ }, {
8191
+ results: Record<string, {
8192
+ sent: string[];
8193
+ error?: string | undefined;
8194
+ }>;
8195
+ }>;
8196
+ };
8101
8197
  "bulkEngagement-clearRenewalEmailTasks": {
8102
8198
  request: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
8103
8199
  response: z.ZodObject<{
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.1251",
5
+ "version": "1.400.1253",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
8
  "scripts": {
@@ -3,7 +3,15 @@ jest.mock("./firebase/firebaseQuery", () => ({__esModule: true, default: class {
3
3
 
4
4
  import {InstituteData} from "./typeDefinitions";
5
5
  import {resolveProducts} from "./productResolver";
6
- import {bulkEngagementSuggestion} from "./bulkEngagement";
6
+ import {
7
+ BULK_ENGAGEMENT_PACKAGE_LABELS,
8
+ BULK_ENGAGEMENT_PRODUCTS,
9
+ BULK_ENGAGEMENT_PRODUCT_LABELS,
10
+ BULK_TEST_SCHOOLS,
11
+ bulkEngagementSuggestion,
12
+ matchesBulkFilters,
13
+ } from "./bulkEngagement";
14
+ import {engagementCallables} from "./callables/engagement";
7
15
 
8
16
  const school = (renewalDate?: string, overrides: Partial<InstituteData> = {}): InstituteData => ({
9
17
  name: "Calder Park Academy",
@@ -70,3 +78,69 @@ describe("bulk engagement suggestions", () => {
70
78
  expect(suggest("engagementPickFeatures", school(), "2026-11-04", {nextOnboardingTemplate: "engagementPlanYear"}).suggested).toBe(false);
71
79
  });
72
80
  });
81
+
82
+ describe("matchesBulkFilters", () => {
83
+ const trust = {package: "institutes-two", products: ["wex", "destinations"]};
84
+ const hub = {package: "careersHub", products: ["employerEvents"]};
85
+ const none = {package: "institutes-one", products: []};
86
+
87
+ it("matches everything when nothing is ticked", () => {
88
+ [trust, hub, none].forEach((s) => expect(matchesBulkFilters(s, {packages: [], products: []})).toBe(true));
89
+ });
90
+
91
+ it("matches a package that is one of those ticked", () => {
92
+ const packages = ["institutes-two", "careersHub"];
93
+ expect(matchesBulkFilters(trust, {packages, products: []})).toBe(true);
94
+ expect(matchesBulkFilters(hub, {packages, products: []})).toBe(true);
95
+ expect(matchesBulkFilters(none, {packages, products: []})).toBe(false);
96
+ });
97
+
98
+ it("matches a school with any of the products ticked, not all of them", () => {
99
+ expect(matchesBulkFilters(trust, {packages: [], products: ["destinations", "employerEvents"]})).toBe(true);
100
+ expect(matchesBulkFilters(trust, {packages: [], products: ["employerEvents"]})).toBe(false);
101
+ });
102
+
103
+ it("never matches a school with no products once a product is ticked", () => {
104
+ expect(matchesBulkFilters(none, {packages: [], products: ["wex"]})).toBe(false);
105
+ });
106
+
107
+ it("needs both filters to pass", () => {
108
+ expect(matchesBulkFilters(trust, {packages: ["institutes-two"], products: ["wex"]})).toBe(true);
109
+ expect(matchesBulkFilters(trust, {packages: ["careersHub"], products: ["wex"]})).toBe(false);
110
+ expect(matchesBulkFilters(trust, {packages: ["institutes-two"], products: ["employerEvents"]})).toBe(false);
111
+ });
112
+
113
+ it("labels every package and product in sentence case", () => {
114
+ expect(BULK_ENGAGEMENT_PACKAGE_LABELS).toEqual({
115
+ "institutes-one": "School",
116
+ "institutes-two": "Trust",
117
+ "careersHub": "Careers hub",
118
+ "careersSchool": "Hub school",
119
+ });
120
+ expect(BULK_ENGAGEMENT_PRODUCTS.map((p) => BULK_ENGAGEMENT_PRODUCT_LABELS[p])).toEqual(["Work experience", "Employer events", "Destinations"]);
121
+ });
122
+
123
+ it("offers products that resolveProducts sets", () => {
124
+ const products = resolveProducts({package: "careersHub", workExperience: true});
125
+ expect(BULK_ENGAGEMENT_PRODUCTS.filter((p) => products[p])).toEqual(["employerEvents"]);
126
+ });
127
+ });
128
+
129
+ describe("sendBulkEngagementTest contract", () => {
130
+ const request = (count: number) => ({
131
+ templateKey: "engagementRenewalDue",
132
+ oIds: Array.from({length: count}, (_, i) => `school-${i}`),
133
+ subject: "Renewing",
134
+ body: [{type: "paragraph"}],
135
+ });
136
+ const contract = engagementCallables["bulkEngagement-sendBulkEngagementTest"].request;
137
+
138
+ it("takes up to BULK_TEST_SCHOOLS schools and no more", () => {
139
+ expect(contract.safeParse(request(BULK_TEST_SCHOOLS)).success).toBe(true);
140
+ expect(contract.safeParse(request(BULK_TEST_SCHOOLS + 1)).success).toBe(false);
141
+ });
142
+
143
+ it("has no way to name a recipient", () => {
144
+ expect(contract.parse({...request(1), to: "someone@school.sch.uk"})).not.toHaveProperty("to");
145
+ });
146
+ });
@@ -25,6 +25,34 @@ export const BULK_ENGAGEMENT_FLAG_LABELS: Record<BulkEngagementFlag, string> = {
25
25
  /** Flags that stop a school being sent the email at all. */
26
26
  export const BULK_ENGAGEMENT_BLOCKING_FLAGS: BulkEngagementFlag[] = ["noContacts"];
27
27
 
28
+ /** The account types the send popup filters by, and what it calls them. */
29
+ export const BULK_ENGAGEMENT_PACKAGE_LABELS: {[pkg: string]: string} = {
30
+ "institutes-one": "School",
31
+ "institutes-two": "Trust",
32
+ "careersHub": "Careers hub",
33
+ "careersSchool": "Hub school",
34
+ };
35
+
36
+ /** The products the send popup filters by. Flags on ResolvedProducts. */
37
+ export type BulkEngagementProduct = "wex"|"employerEvents"|"destinations";
38
+
39
+ export const BULK_ENGAGEMENT_PRODUCTS: BulkEngagementProduct[] = ["wex", "employerEvents", "destinations"];
40
+
41
+ export const BULK_ENGAGEMENT_PRODUCT_LABELS: Record<BulkEngagementProduct, string> = {
42
+ wex: "Work experience",
43
+ employerEvents: "Employer events",
44
+ destinations: "Destinations",
45
+ };
46
+
47
+ /** What the admin has ticked in the send popup's filters. Empty means any. */
48
+ export type BulkEngagementFilters = {packages: string[], products: string[]};
49
+
50
+ /** Who the popup's "Send test" goes to. Fixed on the server, never taken from the request. */
51
+ export const BULK_TEST_RECIPIENT = "tom@careerthread.co.uk";
52
+
53
+ /** How many schools' copies one test sends. Matches the cap in the callable's contract. */
54
+ export const BULK_TEST_SCHOOLS = 3;
55
+
28
56
  /** A school that had this email this recently isn't suggested it again. */
29
57
  export const RECENTLY_SENT_DAYS = 60;
30
58
 
@@ -98,3 +126,19 @@ export const bulkEngagementSuggestion = (templateKey: string, school: BulkEngage
98
126
  if (days === undefined || days < window[0] || days > window[1]) return none;
99
127
  return {suggested: true, reason: `Renews in ${days} days`, flags};
100
128
  };
129
+
130
+ /**
131
+ * Whether a school passes the send popup's filters: its package is one of
132
+ * those ticked, and it has any of the products ticked. An empty filter
133
+ * matches everything.
134
+ *
135
+ * @param {object} school the school's package and products.
136
+ * @param {BulkEngagementFilters} filters what is ticked.
137
+ * @return {boolean} whether the school matches.
138
+ */
139
+ export const matchesBulkFilters = (
140
+ school: {package: string, products: string[]},
141
+ {packages, products}: BulkEngagementFilters,
142
+ ): boolean =>
143
+ (!packages.length || packages.includes(school.package)) &&
144
+ (!products.length || products.some((p) => school.products.includes(p)));
@@ -11,6 +11,7 @@ import {CallableGroup, optionalField} from "./types";
11
11
  */
12
12
 
13
13
  const flag = z.enum(["noContacts", "noRenewalDate", "noQuote", "noFinanceContact", "sentRecently"]);
14
+ const product = z.enum(["wex", "employerEvents", "destinations"]);
14
15
 
15
16
  export const engagementCallables = {
16
17
  "bulkEngagement-getBulkEngagementSchools": {
@@ -23,6 +24,8 @@ export const engagementCallables = {
23
24
  oId: z.string(),
24
25
  name: z.string(),
25
26
  package: z.string(),
27
+ /** The products the admin can filter this school by. */
28
+ products: z.array(product),
26
29
  suggested: z.boolean(),
27
30
  reason: z.string().optional(),
28
31
  flags: z.array(flag),
@@ -52,6 +55,23 @@ export const engagementCallables = {
52
55
  results: z.record(z.string(), z.object({sent: z.array(z.string()), error: z.string().optional()})),
53
56
  }),
54
57
  },
58
+ /**
59
+ * Sends each school's copy of the email to CareerThread's test address, so
60
+ * it can be read before the real send. Nothing is logged on the school or
61
+ * changed on it, and no follow-ups start. The address is set on the server.
62
+ */
63
+ "bulkEngagement-sendBulkEngagementTest": {
64
+ request: z.object({
65
+ templateKey: z.string().min(1),
66
+ oIds: z.array(z.string().min(1)).min(1, "Pick at least one school.").max(3),
67
+ subject: z.string().trim().min(1, "Give it a subject."),
68
+ body: z.array(z.unknown()).min(1),
69
+ heroImage: optionalField(z.string()),
70
+ }),
71
+ response: z.object({
72
+ results: z.record(z.string(), z.object({sent: z.array(z.string()), error: z.string().optional()})),
73
+ }),
74
+ },
55
75
  /** One-off: removes the open renewal email tasks the old automatic schedule made. */
56
76
  "bulkEngagement-clearRenewalEmailTasks": {
57
77
  request: z.object({}).optional(),