placementt-core 11.0.892 → 11.0.951
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +47 -1
- package/lib/constants.js.map +1 -1
- package/lib/hooks.d.ts +57 -15
- package/lib/hooks.js +217 -43
- package/lib/hooks.js.map +1 -1
- package/lib/typeDefinitions.d.ts +91 -4
- package/lib/util.d.ts +25 -1
- package/lib/util.js +329 -2
- package/lib/util.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +49 -0
- package/src/hooks.tsx +247 -47
- package/src/typeDefinitions.ts +96 -20
- package/src/util.ts +350 -4
package/src/typeDefinitions.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {DocumentData, DocumentReference, Timestamp} from "firebase/firestore";
|
|
2
2
|
import {Descendant} from "slate";
|
|
3
3
|
import {emailTemplates} from "./constants";
|
|
4
|
+
import {FilterObject} from "./hooks";
|
|
4
5
|
|
|
5
6
|
export type Products = "institutes"|"providers"|"students"|"admin";
|
|
6
7
|
|
|
@@ -21,6 +22,7 @@ export type StudentPlacementData = {
|
|
|
21
22
|
providerEmailed: Timestamp,
|
|
22
23
|
parentEmailed: Timestamp,
|
|
23
24
|
providerPhone: string,
|
|
25
|
+
studentDescription?: string,
|
|
24
26
|
website?: string,
|
|
25
27
|
id:string,
|
|
26
28
|
providerCompleted: string[],
|
|
@@ -142,17 +144,17 @@ export type PlacementQuestions = {
|
|
|
142
144
|
payFrequency: "total"|"hourly"|"daily"|"weekly"|"monthly"|"annually",
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
export type SavedPlacement = {
|
|
148
|
+
placementId: string,
|
|
149
|
+
savedByProduct: Products,
|
|
150
|
+
savedByUserType: "Organisation"|"Student",
|
|
151
|
+
savedById: string,
|
|
152
|
+
schoolId?: string,
|
|
153
|
+
status?: "Accepted" | "Blocked" | "providerReview";
|
|
154
|
+
listed: boolean,
|
|
155
|
+
concurrentPlacements?: number,
|
|
156
|
+
id: string
|
|
157
|
+
}
|
|
156
158
|
|
|
157
159
|
// export type PlacementListingStages = "basic"|"address"|"students"|"responsibilities"|"applications"|"onboarding"|"review"|"complete";
|
|
158
160
|
|
|
@@ -368,9 +370,24 @@ export type UserData = {
|
|
|
368
370
|
provider: number[],
|
|
369
371
|
student: number[],
|
|
370
372
|
}},
|
|
371
|
-
alumniConversationUid?: string
|
|
373
|
+
alumniConversationUid?: string,
|
|
374
|
+
savedDataViewerFilters?: {
|
|
375
|
+
[cohortId: string]: {
|
|
376
|
+
[key in "cohortPlacements"|"cohortStudents"]: {
|
|
377
|
+
[viewKey: string]: DataViewerFilterView
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
372
381
|
};
|
|
373
382
|
|
|
383
|
+
export type DataViewerFilterView = {
|
|
384
|
+
title: string,
|
|
385
|
+
search?: string,
|
|
386
|
+
sort?: string,
|
|
387
|
+
filters?: FilterObject,
|
|
388
|
+
permanent?: boolean,
|
|
389
|
+
}
|
|
390
|
+
|
|
374
391
|
export type AnalyticsItem = {
|
|
375
392
|
units?: "placements"|"weeks"|"days"|"hours",
|
|
376
393
|
name?: string
|
|
@@ -593,7 +610,7 @@ export type ProviderContactData = {
|
|
|
593
610
|
insuranceExpiry?: string,
|
|
594
611
|
savedBy?: {[key:string]: {
|
|
595
612
|
exists: true,
|
|
596
|
-
activities?: string[], // IDs of consented activities.
|
|
613
|
+
activities?: null|string[], // IDs of consented activities.
|
|
597
614
|
providerConsent?: boolean,
|
|
598
615
|
providerConsentDate?: string,
|
|
599
616
|
MATschools?: string[],
|
|
@@ -638,7 +655,8 @@ export type InstituteData = {
|
|
|
638
655
|
shareAlumni?: boolean
|
|
639
656
|
approveAlumniMessages?: boolean,
|
|
640
657
|
anonymiseAlumniConvoStudents?: boolean,
|
|
641
|
-
alumniConversations?: boolean
|
|
658
|
+
alumniConversations?: boolean,
|
|
659
|
+
activityInvitesSent?: string
|
|
642
660
|
}&Address;
|
|
643
661
|
|
|
644
662
|
export type ExternalActivity = {
|
|
@@ -651,7 +669,8 @@ export type ExternalActivity = {
|
|
|
651
669
|
oId?: string,
|
|
652
670
|
alumni?: boolean,
|
|
653
671
|
provider?: boolean,
|
|
654
|
-
permanent?: boolean
|
|
672
|
+
permanent?: boolean,
|
|
673
|
+
activityType: "workExperience"|"workplaceVisits"|"mentoring"|"mockInterviews"|"other"
|
|
655
674
|
}
|
|
656
675
|
|
|
657
676
|
export type NotificationObject = {
|
|
@@ -706,7 +725,7 @@ export type StaffRoles = {
|
|
|
706
725
|
staff: string[]
|
|
707
726
|
};
|
|
708
727
|
|
|
709
|
-
export type QueryObjectConstraint = [string, "=="|"<"|"<="|">="|">"|"!="|"array-contains"|"array-contains-any"|"in"|"not-in", string|boolean][]
|
|
728
|
+
export type QueryObjectConstraint = [string, "=="|"<"|"<="|">="|">"|"!="|"array-contains"|"array-contains-any"|"in"|"not-in", string|boolean|string[]][]
|
|
710
729
|
|
|
711
730
|
export type QueryObject = {
|
|
712
731
|
path: string[],
|
|
@@ -762,7 +781,7 @@ export type CohortData = {
|
|
|
762
781
|
endSubmission: string,
|
|
763
782
|
startPlacements: string,
|
|
764
783
|
endPlacements: string,
|
|
765
|
-
stage: "info"|"name"|"placementType"|"students"|"workflow"|"review"|"created"|"archived",
|
|
784
|
+
stage: "info"|"name"|"placementType"|"students"|"workflow"|"review"|"created"|"archived"|"database",
|
|
766
785
|
workflow: WorkflowStage[]
|
|
767
786
|
customWorkflow?: boolean,
|
|
768
787
|
oId: string,
|
|
@@ -771,6 +790,8 @@ export type CohortData = {
|
|
|
771
790
|
designatedStaff?: string,
|
|
772
791
|
autoArchiveDate?: string,
|
|
773
792
|
logType?: "basic"|"custom",
|
|
793
|
+
listingReleaseDate?: string,
|
|
794
|
+
enableListings?: boolean,
|
|
774
795
|
logs?: {
|
|
775
796
|
students?: string,
|
|
776
797
|
staff?: string,
|
|
@@ -789,7 +810,16 @@ export type CohortData = {
|
|
|
789
810
|
providerFeedbackSent?: Timestamp,
|
|
790
811
|
studentsFeedbackSent?: Timestamp,
|
|
791
812
|
emailTemplates?: {[key in keyof typeof emailTemplates]: string},
|
|
792
|
-
skillsTargets?: string[]
|
|
813
|
+
skillsTargets?: string[],
|
|
814
|
+
recurringEmails?: {
|
|
815
|
+
sendType?: "all"|"lastWeek",
|
|
816
|
+
frequency?: "oneTime"|"weeklyMonday"|"fortnightlyMonday"
|
|
817
|
+
},
|
|
818
|
+
savedDataViewerFilters?: {
|
|
819
|
+
[key in "cohortPlacements"|"cohortStudents"]: {
|
|
820
|
+
[key: string]: DataViewerFilterView
|
|
821
|
+
}
|
|
822
|
+
}
|
|
793
823
|
}
|
|
794
824
|
|
|
795
825
|
export type ArrowObject = {
|
|
@@ -863,7 +893,10 @@ export type PlacementReviewDetails = {
|
|
|
863
893
|
feedback: CustomFormSchema,
|
|
864
894
|
providerFeedback?: {[key: string]: unknown},
|
|
865
895
|
primaryColor?: string,
|
|
866
|
-
primaryImage?: string
|
|
896
|
+
primaryImage?: string,
|
|
897
|
+
savedBySchool?: boolean,
|
|
898
|
+
consentedActivities?: string[],
|
|
899
|
+
instituteActivities?: {[key: string]: ExternalActivity}
|
|
867
900
|
}
|
|
868
901
|
|
|
869
902
|
export type BlogCategories = "students"|"providers"|"institutes"|"placementt"
|
|
@@ -1016,7 +1049,7 @@ export type EmailTemplateConfig = {
|
|
|
1016
1049
|
description: string,
|
|
1017
1050
|
params: string[],
|
|
1018
1051
|
button?: {text: string, link: string},
|
|
1019
|
-
type: "workflow"|"feedback"
|
|
1052
|
+
type: "workflow"|"feedback"|"event"
|
|
1020
1053
|
}
|
|
1021
1054
|
|
|
1022
1055
|
|
|
@@ -1059,10 +1092,16 @@ export type SchoolData = OrganisationAddress&{
|
|
|
1059
1092
|
export type ExternalEvent = {
|
|
1060
1093
|
name: string,
|
|
1061
1094
|
description: string,
|
|
1095
|
+
staffInformation?: string,
|
|
1096
|
+
studentInformation?: string,
|
|
1097
|
+
employerInformation?: string
|
|
1098
|
+
designatedStaff: string,
|
|
1062
1099
|
created: string,
|
|
1063
1100
|
activityId?: string,
|
|
1101
|
+
gatsbyBenchmarks?: string, // String array
|
|
1064
1102
|
oId: string,
|
|
1065
1103
|
submissionClose: string,
|
|
1104
|
+
acceptingEmployers?: boolean,
|
|
1066
1105
|
schoolId?: string,
|
|
1067
1106
|
startDate?: string,
|
|
1068
1107
|
endDate?: string,
|
|
@@ -1082,7 +1121,24 @@ export type ExternalEvent = {
|
|
|
1082
1121
|
employers: {
|
|
1083
1122
|
shareable?: boolean,
|
|
1084
1123
|
filters: {[key: string]: unknown}
|
|
1124
|
+
},
|
|
1125
|
+
employerFeedback: {
|
|
1126
|
+
files: string[],
|
|
1127
|
+
forms: string[],
|
|
1128
|
+
requiredFiles: {
|
|
1129
|
+
fileName: string,
|
|
1130
|
+
fileType: string
|
|
1131
|
+
}[],
|
|
1132
|
+
},
|
|
1133
|
+
studentFeedback: {
|
|
1134
|
+
files: string[],
|
|
1135
|
+
forms: string[],
|
|
1136
|
+
requiredFiles: {
|
|
1137
|
+
fileName: string,
|
|
1138
|
+
fileType: string
|
|
1139
|
+
}[],
|
|
1085
1140
|
}
|
|
1141
|
+
completedStages: ("basicDetails"|"employerInvites"|"studentInvites"|"employerSelection"|"feedback")[]
|
|
1086
1142
|
}&Address
|
|
1087
1143
|
|
|
1088
1144
|
|
|
@@ -1160,4 +1216,24 @@ export type Update = {
|
|
|
1160
1216
|
buttonLink?: string,
|
|
1161
1217
|
date: string,
|
|
1162
1218
|
imageData?: boolean
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
export type ExternalEventAttendee = {
|
|
1224
|
+
oId: string,
|
|
1225
|
+
eventId: string,
|
|
1226
|
+
providerContactId: string,
|
|
1227
|
+
status: "invited"|"providerAvailable"|"finalConfirmationSent"|"providerConfirmed"|"feedbackSent"
|
|
1228
|
+
emails: {
|
|
1229
|
+
[k in "invited"|"finalConfirmationSent"|"feedbackSent"]: {
|
|
1230
|
+
sent: number, // If below 3, keep sending reminders.
|
|
1231
|
+
reconciled: string|boolean,
|
|
1232
|
+
log: {
|
|
1233
|
+
[k: string]: string // emailNumber_dateTimeString : eventType
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
attended?: boolean,
|
|
1238
|
+
feedback: {[key: string]: unknown}
|
|
1163
1239
|
}
|
package/src/util.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {where} from "firebase/firestore";
|
|
2
2
|
import FirebaseQuery from "./firebase/firebaseQuery";
|
|
3
|
-
import {AlumniConversation, FlagCodes, InstituteData, StudentPlacementData, UserData, WorkflowStage} from "./typeDefinitions";
|
|
3
|
+
import {AlumniConversation, EmailTemplateConfig, FlagCodes, InstituteData, StudentPlacementData, UserData, WorkflowStage} from "./typeDefinitions";
|
|
4
4
|
import {convertDate} from "./firebase/util";
|
|
5
|
+
import {Descendant} from "slate";
|
|
6
|
+
import {PRIMARY_COLOUR} from "./constants";
|
|
5
7
|
|
|
6
8
|
type PlacementFlagCodeParams = {
|
|
7
9
|
placement : StudentPlacementData, // Placement we get flag codes for
|
|
@@ -33,8 +35,8 @@ export const getPlacementFlagCodes = async ({placement, studentData, workflow, i
|
|
|
33
35
|
// If placement after provider review and not verified
|
|
34
36
|
const placementIsPostProviderReview = placement.leadTimes.some((x) => x.split("_")[0] === "3");
|
|
35
37
|
const placementNotEnded = !placement.leadTimes.some((x) => x.split("_")[0] === "8");
|
|
36
|
-
const providerUnverified = placement.
|
|
37
|
-
const awaitingProviderInsurance = placement.
|
|
38
|
+
const providerUnverified = placement.providerContactId && !institute?.verifiedProviders?.includes(placement.providerContactId);
|
|
39
|
+
const awaitingProviderInsurance = placement.providerContactId && institute?.awaitingProviderInsurance?.includes(placement.providerContactId);
|
|
38
40
|
|
|
39
41
|
const riskAssessmentNotVerified = !institute?.verifiedRiskAssessments?.includes(placement.placementId || placement.id);
|
|
40
42
|
const awaitingRiskAssessment = !placement.riskAssessment || institute?.awaitingPlacementRiskAssessments?.includes(placement.placementId || placement.id);
|
|
@@ -174,4 +176,348 @@ export const getMostRecentAlumniMessage = (conversation: AlumniConversation) =>
|
|
|
174
176
|
.sort((a, b) => new Date(b.sentAt).getTime() - new Date(a.sentAt).getTime())[0];
|
|
175
177
|
|
|
176
178
|
return mostRecent || null; // Return most recent or null if none found
|
|
177
|
-
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
export function buildEmailHTML({preheader, title, salutation, body, primaryColor=PRIMARY_COLOUR, secondaryBody, primaryButton, secondaryButton, primaryImage="http://cdn.mcauto-images-production.sendgrid.net/d17240a596025cf2/637d5af1-79d2-42c9-a663-e88abfea32b9/686x143.png", designatedStaffEmail, organisationName, params, data}:{preheader: string, title: string, salutation?: string, body: string|Descendant[], primaryColor?: string, secondaryBody?: string, primaryButton?: {title: string, url: string}, secondaryButton?: {title: string, url: string}, primaryImage?: string, designatedStaffEmail?: string, organisationName?: string, params?: EmailTemplateConfig, data?: {[key: string]: string|undefined}}) {
|
|
183
|
+
const serialiseSlate = (nodes: Descendant[]) => {
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
return nodes.map((n:any) => {
|
|
186
|
+
if (n.type === "paragraph") {
|
|
187
|
+
const text:string[]=[];
|
|
188
|
+
for (let i = 0; i < n.children.length; i++) {
|
|
189
|
+
const item = n.children[i];
|
|
190
|
+
let subtext = item.text as string || "<br/>";
|
|
191
|
+
console.log("serialise text", subtext);
|
|
192
|
+
|
|
193
|
+
subtext = subtext.replace("", "");
|
|
194
|
+
if (item.underline) {
|
|
195
|
+
subtext = `<u>${subtext}</u>`;
|
|
196
|
+
}
|
|
197
|
+
if (item.bold) {
|
|
198
|
+
subtext = `<strong>${subtext}</strong>`;
|
|
199
|
+
}
|
|
200
|
+
if (item.italic) {
|
|
201
|
+
subtext = `<i>${subtext}</i>`;
|
|
202
|
+
}
|
|
203
|
+
text.push(subtext);
|
|
204
|
+
}
|
|
205
|
+
return `<div style="font-family: inherit; text-align: inherit">${text.join("")}</div>`;
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}).filter((a) => a).join("<div style=\"font-family: inherit; text-align: inherit\"><br></div>");
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const getEmailContentFromTemplate = (template: string|Descendant[], params: EmailTemplateConfig, data: {[key: string]: string|undefined}) => {
|
|
212
|
+
let finalBody = typeof template === "string" ? template : serialiseSlate(template);
|
|
213
|
+
console.log("Body before processing", finalBody);
|
|
214
|
+
|
|
215
|
+
// Replace all instances of placeholder with actual data.
|
|
216
|
+
[...params.params, ...Object.keys(data)].forEach((param) => {
|
|
217
|
+
console.log(`Replacing {{${param}}} with "${data[param]}"`);
|
|
218
|
+
finalBody = finalBody.replace(`{{${param}}}`, data[param] as string);
|
|
219
|
+
});
|
|
220
|
+
console.log("Processed body", finalBody);
|
|
221
|
+
// Still have the {{button}} elements to replace. In this case, split the string up between the button elements.
|
|
222
|
+
const itemsInBody = finalBody.split(/(\{\{button\}\})/);
|
|
223
|
+
|
|
224
|
+
const itemsInBodyWithFormattedButtons = itemsInBody.map((item) => {
|
|
225
|
+
if (item !== "{{button}}" || !params.button) return item;
|
|
226
|
+
|
|
227
|
+
let title = params.button.text;
|
|
228
|
+
let url = "https://placementt.co.uk"+params.button.link;
|
|
229
|
+
|
|
230
|
+
// Replace any params in the url or title with the relevant data.
|
|
231
|
+
[...params.params, ...Object.keys(data)].forEach((param) => {
|
|
232
|
+
title = title.replace(`{{${param}}}`, data[param] as string);
|
|
233
|
+
});
|
|
234
|
+
[...params.params, ...Object.keys(data)].forEach((param) => {
|
|
235
|
+
url = url.replace(`{{${param}}}`, data[param] as string);
|
|
236
|
+
});
|
|
237
|
+
return {
|
|
238
|
+
title: title,
|
|
239
|
+
url: url,
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return itemsInBodyWithFormattedButtons;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
let formattedBody = (params && data) ? "" : body;
|
|
247
|
+
let formattedSecondaryBody = (params && data) ? "" : secondaryBody;
|
|
248
|
+
let formattedPrimaryButton = (params && data) ? undefined : primaryButton;
|
|
249
|
+
let formattedSecondaryButton = (params && data) ? undefined : secondaryButton;
|
|
250
|
+
|
|
251
|
+
if (params && data) {
|
|
252
|
+
const processedBody = getEmailContentFromTemplate(body, params, data);
|
|
253
|
+
|
|
254
|
+
processedBody.forEach((item) => {
|
|
255
|
+
if (typeof item === "string") {
|
|
256
|
+
if (!formattedBody) {
|
|
257
|
+
formattedBody = item;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
formattedSecondaryBody = item;
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// Must be a button
|
|
264
|
+
if (!formattedPrimaryButton) {
|
|
265
|
+
formattedPrimaryButton = item;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
formattedSecondaryButton = item;
|
|
269
|
+
});
|
|
270
|
+
formattedBody = processedBody[0] as string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const emailHeadAndStylesHTML = `
|
|
274
|
+
<head>
|
|
275
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
276
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
|
|
277
|
+
<!--[if !mso]><!-->
|
|
278
|
+
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
|
279
|
+
<!--<![endif]--><!--[if (gte mso 9)|(IE)]>
|
|
280
|
+
<xml>
|
|
281
|
+
<o:OfficeDocumentSettings>
|
|
282
|
+
<o:AllowPNG/>
|
|
283
|
+
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
284
|
+
</o:OfficeDocumentSettings>
|
|
285
|
+
</xml>
|
|
286
|
+
<![endif]--><!--[if (gte mso 9)|(IE)]>
|
|
287
|
+
<style type="text/css"> body {width: 600px;margin: 0 auto;} table {border-collapse: collapse;} table, td {mso-table-lspace: 0pt;mso-table-rspace: 0pt;} img {-ms-interpolation-mode: bicubic;} </style>
|
|
288
|
+
<![endif]-->
|
|
289
|
+
<style type="text/css"> body, p, div {font-family: inherit;font-size: 14px;} body {color: #000000;} body a {color: #000000;text-decoration: none;} p { margin: 0; padding: 0; } table.wrapper {width:100% !important;table-layout: fixed;-webkit-font-smoothing: antialiased;-webkit-text-size-adjust: 100%;-moz-text-size-adjust: 100%;-ms-text-size-adjust: 100%;} img.max-width {max-width: 100% !important;} .column.of-2 {width: 50%;} .column.of-3 {width: 33.333%;} .column.of-4 {width: 25%;} ul ul ul ul {list-style-type: disc !important;} ol ol {list-style-type: lower-roman !important;} ol ol ol {list-style-type: lower-latin !important;} ol ol ol ol {list-style-type: decimal !important;} @media screen and (max-width:480px) {.preheader .rightColumnContent, .footer .rightColumnContent {text-align: left !important;} .preheader .rightColumnContent div, .preheader .rightColumnContent span, .footer .rightColumnContent div, .footer .rightColumnContent span {text-align: left !important;} .preheader .rightColumnContent, .preheader .leftColumnContent {font-size: 80% !important;padding: 5px 0;} table.wrapper-mobile {width: 100% !important;table-layout: fixed;} img.max-width {height: auto !important;max-width: 100% !important;} a.bulletproof-button {display: block !important;width: auto !important;font-size: 80%;padding-left: 0 !important;padding-right: 0 !important;} .columns {width: 100% !important;} .column {display: block !important;width: 100% !important;padding-left: 0 !important;padding-right: 0 !important;margin-left: 0 !important;margin-right: 0 !important;} .social-icon-column {display: inline-block !important;} } </style>
|
|
290
|
+
<style> @media screen and (max-width:480px) {table\0 {width: 480px !important;} } </style>
|
|
291
|
+
<!--user entered Head Start-->
|
|
292
|
+
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
|
|
293
|
+
<style> * {font-family: 'nunito', sans-serif;} </style>
|
|
294
|
+
<!--End Head user entered-->
|
|
295
|
+
</head>
|
|
296
|
+
`;
|
|
297
|
+
|
|
298
|
+
const primaryButtonTextLinkHTML = formattedPrimaryButton ? `
|
|
299
|
+
<tr>
|
|
300
|
+
<td style="padding:0px 15px 0px 15px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
301
|
+
<div>
|
|
302
|
+
<div style="font-family: inherit; text-align: inherit">Or go to <a href="${formattedPrimaryButton.url}">${formattedPrimaryButton.url}</a></div>
|
|
303
|
+
<div></div>
|
|
304
|
+
</div>
|
|
305
|
+
</td>
|
|
306
|
+
</tr>` : "";
|
|
307
|
+
|
|
308
|
+
const primaryButtonHTML = formattedPrimaryButton ? `
|
|
309
|
+
<tr>
|
|
310
|
+
<td align="center" bgcolor="${primaryColor}" class="inner-td" style="border-radius:6px; font-size:16px; text-align:center; background-color:inherit;"><a href="${formattedPrimaryButton.url}" style="background-color:${primaryColor}; border:1px solid #ffffff; border-color:#ffffff; border-radius:30px; border-width:1px; color:#ffffff; display:inline-block; font-size:16px; font-weight:normal; letter-spacing:0px; line-height:normal; padding:12px 40px 12px 40px; text-align:center; text-decoration:none; border-style:solid; font-family:nunito,sans-serif;" target="_blank">${formattedPrimaryButton.title}</a></td>
|
|
311
|
+
</tr>` : "";
|
|
312
|
+
|
|
313
|
+
const secondaryButtonTextHTML = formattedSecondaryButton ? `
|
|
314
|
+
<tr>
|
|
315
|
+
<td align="center" class="inner-td" style="text-align:center; background-color:inherit;"><a href="${formattedSecondaryButton.url}" style="display:inline-block; font-weight:normal; color:#aeaeae; letter-spacing:0px; line-height:normal; text-align:center; text-decoration:none; font-family:nunito,sans-serif;" target="_blank">${formattedSecondaryButton.title}</a></td>
|
|
316
|
+
</tr>` : "";
|
|
317
|
+
|
|
318
|
+
const buttonTableHTML = (primaryButtonHTML || secondaryButtonTextHTML) ? `
|
|
319
|
+
<table border="0" cellpadding="0" cellspacing="0" class="module" data-role="module-button" data-type="button" role="module" style="table-layout:fixed;" width="100%" data-muid="3757586a-ce69-48ba-bd9a-0c0b7937a616">
|
|
320
|
+
<tbody>
|
|
321
|
+
<tr>
|
|
322
|
+
<td align="center" bgcolor="" class="outer-td" style="padding:0px 0px 40px 0px;">
|
|
323
|
+
<table border="0" cellpadding="0" cellspacing="0" class="wrapper-mobile" style="text-align:center;">
|
|
324
|
+
<tbody>
|
|
325
|
+
${primaryButtonHTML}
|
|
326
|
+
${secondaryButtonTextHTML}
|
|
327
|
+
</tbody>
|
|
328
|
+
</table>
|
|
329
|
+
</td>
|
|
330
|
+
</tr>
|
|
331
|
+
${primaryButtonTextLinkHTML}
|
|
332
|
+
</tbody>
|
|
333
|
+
</table>` : "";
|
|
334
|
+
|
|
335
|
+
const secondaryBodyHTML = formattedSecondaryBody ? `
|
|
336
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="c589a68d-fd31-4291-b822-cddb80753f13" data-mc-module-version="2019-10-22">
|
|
337
|
+
<tbody>
|
|
338
|
+
<tr>
|
|
339
|
+
<td style="padding:0px 15px 0px 15px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
340
|
+
<div>
|
|
341
|
+
<div style="font-family: inherit; text-align: inherit"><br></div>
|
|
342
|
+
<div style="font-family: inherit; text-align: inherit">${formattedSecondaryBody}</div>
|
|
343
|
+
<div></div>
|
|
344
|
+
</div>
|
|
345
|
+
</td>
|
|
346
|
+
</tr>
|
|
347
|
+
</tbody>
|
|
348
|
+
</table>` : "";
|
|
349
|
+
|
|
350
|
+
const organisationContactSentence = (designatedStaffEmail || organisationName) ?
|
|
351
|
+
`
|
|
352
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="50de54bb-94d0-4d21-a7f2-100719150961" data-mc-module-version="2019-10-22">
|
|
353
|
+
<tbody>
|
|
354
|
+
<tr>
|
|
355
|
+
<td style="padding:0px 15px 18px 15px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
356
|
+
<div>
|
|
357
|
+
|
|
358
|
+
<div style="font-family: inherit; text-align: inherit">
|
|
359
|
+
|
|
360
|
+
${organisationName ? `<span style="color: #aeaeae">This email was sent by Placementt on behalf of ${organisationName}.</span>` :
|
|
361
|
+
designatedStaffEmail ? `Please do not reply directly to this email. For any queries, contact <a href="mailto:${designatedStaffEmail}">${designatedStaffEmail}</a>` : ""}
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
</td>
|
|
365
|
+
</tr>
|
|
366
|
+
</tbody>
|
|
367
|
+
</table>` :
|
|
368
|
+
"";
|
|
369
|
+
|
|
370
|
+
return `<html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml">
|
|
371
|
+
${emailHeadAndStylesHTML}
|
|
372
|
+
<body>
|
|
373
|
+
<center class="wrapper" data-link-color="#000000" data-body-style="font-size:14px; font-family:inherit; color:#000000; background-color:#F9F4FF;">
|
|
374
|
+
<div class="webkit">
|
|
375
|
+
<table cellpadding="0" cellspacing="0" border="0" width="100%" class="wrapper" bgcolor="#F9F4FF">
|
|
376
|
+
<tbody>
|
|
377
|
+
<tr>
|
|
378
|
+
<td valign="top" bgcolor="#F9F4FF" width="100%">
|
|
379
|
+
<table width="100%" role="content-container" class="outer" align="center" cellpadding="0" cellspacing="0" border="0">
|
|
380
|
+
<tbody>
|
|
381
|
+
<tr>
|
|
382
|
+
<td width="100%">
|
|
383
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
|
384
|
+
<tbody>
|
|
385
|
+
<tr>
|
|
386
|
+
<td>
|
|
387
|
+
<!--[if mso]>
|
|
388
|
+
<center>
|
|
389
|
+
<table>
|
|
390
|
+
<tr>
|
|
391
|
+
<td width="600">
|
|
392
|
+
<![endif]-->
|
|
393
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="width:100%; max-width:600px;" align="center">
|
|
394
|
+
<tbody>
|
|
395
|
+
<tr>
|
|
396
|
+
<td role="modules-container" style="padding:0px 0px 0px 0px; color:#000000; text-align:left;" bgcolor="#ffffff" width="100%" align="left">
|
|
397
|
+
<table class="module preheader preheader-hide" role="module" data-type="preheader" border="0" cellpadding="0" cellspacing="0" width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">
|
|
398
|
+
<tbody>
|
|
399
|
+
<tr>
|
|
400
|
+
<td role="module-content">
|
|
401
|
+
<p>${preheader}</p>
|
|
402
|
+
</td>
|
|
403
|
+
</tr>
|
|
404
|
+
</tbody>
|
|
405
|
+
</table>
|
|
406
|
+
<table border="0" cellpadding="0" cellspacing="0" align="center" width="100%" role="module" data-type="columns" style="padding:20px 0px 20px 0px;" bgcolor="#ffffff" data-distribution="1">
|
|
407
|
+
<tbody>
|
|
408
|
+
<tr role="module-content">
|
|
409
|
+
<td height="100%" valign="top">
|
|
410
|
+
<table width="600" style="width:600px; border-spacing:0; border-collapse:collapse; margin:0px 0px 0px 0px;" cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-0">
|
|
411
|
+
<tbody>
|
|
412
|
+
<tr>
|
|
413
|
+
<td style="padding:0px;margin:0px;border-spacing:0;">
|
|
414
|
+
<table class="wrapper" role="module" data-type="image" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="9f29c991-6500-41ef-9f0e-d56cb5dc1238">
|
|
415
|
+
<tbody>
|
|
416
|
+
<tr>
|
|
417
|
+
<td style="font-size:6px; line-height:10px; padding:0px 0px 0px 0px;" valign="top" align="center"><img class="max-width" border="0" style="display:block; color:#000000; text-decoration:none; font-family:Helvetica, arial, sans-serif; font-size:16px; max-width:52% !important; width:52%; height:auto !important; max-height: 100px; object-fit: contain" width="312" alt="" data-proportionally-constrained="false" data-responsive="true" src="${primaryImage}"></td>
|
|
418
|
+
</tr>
|
|
419
|
+
</tbody>
|
|
420
|
+
</table>
|
|
421
|
+
</td>
|
|
422
|
+
</tr>
|
|
423
|
+
</tbody>
|
|
424
|
+
</table>
|
|
425
|
+
</td>
|
|
426
|
+
</tr>
|
|
427
|
+
</tbody>
|
|
428
|
+
</table>
|
|
429
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="b35b8ff4-8b3c-4b35-9ed3-f9f25170affc" data-mc-module-version="2019-10-22">
|
|
430
|
+
<tbody>
|
|
431
|
+
<tr>
|
|
432
|
+
<td style="padding:20px 20px 18px 20px; line-height:28px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
433
|
+
<div>
|
|
434
|
+
<div style="font-family: nunito, sans-serif; text-align: center"><span style="font-size: 24px; font-family: inherit">${title}</span></div>
|
|
435
|
+
<div></div>
|
|
436
|
+
</div>
|
|
437
|
+
</td>
|
|
438
|
+
</tr>
|
|
439
|
+
</tbody>
|
|
440
|
+
</table>
|
|
441
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="c589a68d-fd31-4291-b822-cddb80753f13" data-mc-module-version="2019-10-22">
|
|
442
|
+
<tbody>
|
|
443
|
+
<tr>
|
|
444
|
+
<td style="padding:18px 15px 18px 15px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
445
|
+
<div>
|
|
446
|
+
${salutation ? `<div style="font-family: inherit; text-align: inherit"><span style="color: #000000; font-family: Colfax, Helvetica, Arial, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline">${salutation},</span></div><div style="font-family: inherit; text-align: inherit"><br></div>` : ""}
|
|
447
|
+
<div style="font-family: inherit; text-align: inherit">${formattedBody}</div>
|
|
448
|
+
<div></div>
|
|
449
|
+
</div>
|
|
450
|
+
</td>
|
|
451
|
+
</tr>
|
|
452
|
+
</tbody>
|
|
453
|
+
</table>
|
|
454
|
+
${buttonTableHTML}
|
|
455
|
+
${secondaryBodyHTML}
|
|
456
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="50de54bb-94d0-4d21-a7f2-100719150961" data-mc-module-version="2019-10-22">
|
|
457
|
+
<tbody>
|
|
458
|
+
<tr>
|
|
459
|
+
<td style="padding:18px 15px 9px 15px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content">
|
|
460
|
+
<div>
|
|
461
|
+
<div style="font-family: inherit; text-align: inherit"><span style="color: #aeaeae">If you do not recognise this email, you can safely ignore it.</span></div>
|
|
462
|
+
<div></div>
|
|
463
|
+
</div>
|
|
464
|
+
</td>
|
|
465
|
+
</tr>
|
|
466
|
+
</tbody>
|
|
467
|
+
</table>
|
|
468
|
+
${organisationContactSentence}
|
|
469
|
+
<table border="0" cellpadding="0" cellspacing="0" align="center" width="100%" role="module" data-type="columns" style="padding:0px 0px 0px 0px;" bgcolor="#FFFFFF" data-distribution="1">
|
|
470
|
+
<tbody>
|
|
471
|
+
<tr role="module-content">
|
|
472
|
+
<td height="100%" valign="top">
|
|
473
|
+
<table width="600" style="width:600px; border-spacing:0; border-collapse:collapse; margin:0px 0px 0px 0px;" cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-0">
|
|
474
|
+
<tbody>
|
|
475
|
+
<tr>
|
|
476
|
+
<td style="padding:0px;margin:0px;border-spacing:0;">
|
|
477
|
+
<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="a49405df-a253-4a28-8d3d-be95449c7d30" data-mc-module-version="2019-10-22">
|
|
478
|
+
<tbody>
|
|
479
|
+
<tr>
|
|
480
|
+
<td style="padding:18px 0px 18px 0px; line-height:0px; text-align:inherit; background-color:${primaryColor};" height="100%" valign="top" bgcolor="${primaryColor}" role="module-content">
|
|
481
|
+
<div>
|
|
482
|
+
<div style="font-family: inherit; text-align: center"><a href="http://"><span style="font-size: 12px; color: #ffffff; font-family: inherit">www.placementt.co.uk</span></a></div>
|
|
483
|
+
<div></div>
|
|
484
|
+
</div>
|
|
485
|
+
</td>
|
|
486
|
+
</tr>
|
|
487
|
+
</tbody>
|
|
488
|
+
</table>
|
|
489
|
+
</td>
|
|
490
|
+
</tr>
|
|
491
|
+
</tbody>
|
|
492
|
+
</table>
|
|
493
|
+
</td>
|
|
494
|
+
</tr>
|
|
495
|
+
</tbody>
|
|
496
|
+
</table>
|
|
497
|
+
</td>
|
|
498
|
+
</tr>
|
|
499
|
+
</tbody>
|
|
500
|
+
</table>
|
|
501
|
+
<!--[if mso]>
|
|
502
|
+
</td>
|
|
503
|
+
</tr>
|
|
504
|
+
</table>
|
|
505
|
+
</center>
|
|
506
|
+
<![endif]-->
|
|
507
|
+
</td>
|
|
508
|
+
</tr>
|
|
509
|
+
</tbody>
|
|
510
|
+
</table>
|
|
511
|
+
</td>
|
|
512
|
+
</tr>
|
|
513
|
+
</tbody>
|
|
514
|
+
</table>
|
|
515
|
+
</td>
|
|
516
|
+
</tr>
|
|
517
|
+
</tbody>
|
|
518
|
+
</table>
|
|
519
|
+
</div>
|
|
520
|
+
</center>
|
|
521
|
+
</body>
|
|
522
|
+
</html>`;
|
|
523
|
+
}
|