import {DocumentData, DocumentReference, Timestamp, WhereFilterOp} from "firebase/firestore"; import {Descendant} from "slate"; import {emailTemplates, skillLabelColours} from "./constants"; import {FilterObject} from "./hooks"; export type Products = "institutes"|"providers"|"students"|"admin"; export type StudentPlacementData = { title: string, reqUserType: "Students" | "Staff" | "Provider" | "Parent", lastStageChange?: string // yyyy-mm-dd Set every time a stage changes! uid: string, startDate: string, endDate: string, providerId?: string, name: string, parentKey: string, parentEmail: string, providerKey: string, parentExpiry: string, providerExpiry: string, providerEmail: string, providerEmailed: Timestamp, parentEmailed: Timestamp, providerPhone: string, studentDescription?: string, website?: string, id:string, providerCompleted: string[], oId: string, contactForename: string, contactSurname: string, status: number, nextStatus: number, ["address-line1"]: string, ["address-line2"]: string, locality: string, postal_code: string, what3Words?: string, country: string, cohort?: string, leadTimes: string[], flags?: FlagCodes[], mapConsent: true | false, mapConsentDate?: string, eventsConsent: true | false, eventsConsentDate?: string, placementId?: string, providerContactId?: string, geoHash?: string, statusType: "draft"|"submitted"|"active"|"completed"|"withdrawn"|"requested", questions: PlacementQuestions, staffRoles: string[], sector: string, subsector: string, businessSize: string, importedProviderForms?: boolean, analytics: string[], units: string, schoolId?: string, active: boolean, completed: boolean, personalAnalytics?: string[], completedStages?: number[], contactId?: string created: string, inProgress: boolean, draft: boolean, activeDates: string[], insurance: boolean|"awaitingReview", insuranceExpiry?: string, insuranceSkippedReason?: string, riskAssessment?: boolean|"awaitingReview", riskAssessmentType?: "file"|"form"|"skipped", riskAssessmentData?: {[key:string]: unknown}[]|string, dbsCheck?: boolean|"awaitingReview", dbsCheckType?: "file"|"form"|"skipped", dbsCheckData?: {[key:string]: unknown}[]|string, contactType?: "email"|"website"|"phone"|"post", webpage?: string, providerLogs?: string[], studentsLogs?: string[], notes?: { providers?: Descendant[], institutes?: Descendant[], students?: Descendant[], } staffLogs?: [], feedback: { students: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, parent: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, provider: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, staff: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, }, workingHours: { [date: string]: [string, string]; }; onboarding: (OnboardingDocs&{ deadline?: string, completed: { submitted: boolean, submittedDate?: string, accepted?: boolean, filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string[]}, }})|false|null, studentForename?: string, studentSurname?: string, studentEmail?: string, skillsTargetsValues?: {[key: string]: { provider: number[], student: number[], }} } export type PlacementQuestions = { title: string description: string dressCode: string dressCodeText?: string firstDayContact: string firstAider?: string equipment: string responsibilities: string experiencesGiven: string experienceDesired: string otherAdvice: string carParking: boolean bikeStorage: boolean wheelchairFriendly: boolean kitchen: boolean lunchArrangements?: string hours: any, studentLevel: "gcse"|"college"|"undergraduate"|"postgraduate"|"over18", studentSublevel: string[], desiredLength: number, desiredMinLength?: number, desiredMaxLength?: number, desiredLengthUnits: "days"|"weeks"|"months", maximumStudents: number, workingLocation: "inPerson"|"hybrid"|"remote", pay?: number, payFrequency: "total"|"hourly"|"daily"|"weekly"|"monthly"|"annually", } export type SavedPlacement = { placementId: string, savedByProduct: Products, savedByUserType: "Organisation"|"Student", savedById: string, schoolId?: string, status?: "Accepted" | "Blocked" | "providerReview"; listed: boolean, concurrentPlacements?: number, id: string } // export type PlacementListingStages = "basic"|"address"|"students"|"responsibilities"|"applications"|"onboarding"|"review"|"complete"; export type PlacementListing = { title: string, // uid: string, // template?: string, providerId: string, providerContactId: string, name: string, providerEmail: string, providerPhone: string, id?:string, created?: string, // studentType: "secondary" | "higher" | "undergraduate" | "postgraduate" contactForename: string, contactSurname: string, ["address-line1"]: string, ["address-line2"]: string, locality: string, postal_code: string, country: string, what3Words?: string, geoHash?: string, // status: "listed"|"unlisted"|"deleted"|"draft", questions: PlacementQuestions, savedBy?: {[key:string]: { // LIST OF SCHOOLS THAT HAVE SAVED THIS MATschools?: string[], exists: true, cohorts?: {[key: string]: { exists: boolean, listed: boolean, startDate?: string, studentPlacements?: string[], reservedBy?: string[] concurrentPlacements?: number, }}, eventsConsent?: boolean, eventsConsentDate?: string, providerConsent?: boolean, // Actually consent to placemnts. providerConsentDate?: string, savedByUserType: "Organisation"|"Student", status: "uploaded"|"approved"|"rejected"|"providerReviewed"|"blocked"}}, mapConsent?: boolean, mapConsentDate?: string, uploadedBy: "student"|"institute"|"provider", riskAssessmentType?: "file"|"form"|"skipped", concurrentPlacements?: number, riskAssessmentData?: {[key:string]: unknown}[]|string, dbsCheckType?: "file"|"form"|"skipped", dbsCheckData?: {[key:string]: unknown}[]|string, contactType?: "email"|"website"|"phone"|"post", webpage?: string, sector?: string, subsector?: string, businessSize?: string, // stage: PlacementListingStages, // placementDateType?: "any"|"range"|"defined", // placementDates?: {start: string, end: string}[], // applicationType?: "simple"|"complex", // applicantWorkflowId?: string, // applicantWorkflow?: ApplicantStage[], // onboarding: (OnboardingDocs&{deadline: number})|false, // maxApplicants?: number, // maxStudents?: number, // primaryContactId: string, addressId?: string } export type OnboardingDocs = { message?: string, forms?: string[], files?: string[], requiredFiles?: {fileName: string, fileType: string}[] } // export type PlacementTemplate = PlacementListing&{templateName: string}; export type OrganisationAddressStages = "address"|"contacts"|"misc"|"review"|"complete"; export type OrganisationAddress = Address & { name?: string, savedBy?: string[], product: Products, oId: string, stage: OrganisationAddressStages, additionalQuestions?: { bikeStorage?: boolean, kitchen?: boolean, parking?: boolean, disabledAccess?: boolean, }, contacts?: { firstAid?: { name?: string, phone?: string, email?: string, location?: string }[], security?: { name?: string, phone?: string, email?: string, location?: string }[], reception?: { name?: string, phone?: string, email?: string, location?: string }[], }, primaryContactId?: string, default?: boolean, flags?: ("addressMissing" | "noPrimaryContact")[], color?: string; image?: string|false; }; export type Address = { id?: string, ["address-line1"]: string, ["address-line2"]: string, locality: string, postal_code: string, country: string, geoHash?: string, what3Words?: string }; export type FlagCodes = "inactive" | "noParentEmailWarning" | "noParentEmailError" | "overdue" | "noInsurance" | "providerRejection" | "nearingStart"| "awaitingInsurance"| "noRiskAssessment"| "awaitingRiskAssessment"| "parentEmailFailed"| "providerEmailFailed"| "userEmailFailed"| "noDbsCheck"| "awaitingDbsCheck"| "completeOnboarding"| "reviewOnboarding"| "requestedVisibleAddresses"| "requestedVisiblePlacementListings"| "addOnboarding"| "studentNotAccepted"| "insuranceEarlyExpiry"| "reminder"| "insuranceExpired"| "latePlacementStage"| "stagnantPlacementStage" export type UserData = { details: { forename: string, surname: string, pronouns?: string, parentEmail?: string, year?: string [key: string]: any }, wonde?: { upi: string, id: string, createdDate: Date, updatedDate: Date, restoredDate?: Date, addedDate?: Date, updatedOnDate?: Date, }, passwordReset?: string, renewalMonth: number, placementCharged?: boolean, algoliaKey: string, email: string, phone?: string, status: "active" | "inactive" | "unclaimed", favGuidance?: string[]; oId: string, id: string, resetExpiry?: {seconds: number}, product: Products, userGroup?: string, userType: "Staff"|"Students", created: string, activated: string, groupData?: UserGroupData, staffRoles: string[], flags?: FlagCodes[], cohortRequests: {[oId: string]: string[]}, cohorts: {[oId: string]: string[]}, analytics?: AnalyticsItem, units?: string, activationCode: number, cohort?: string, schoolId?: string, cohortData?: CohortData, dismissedTasks?: string[], dismissedTutorials?: string[], dismissedTips?: string[], dismissedUpdateDate?: string, // A specific date from which all previous updates have been seen. viewCohorts?: "all"|"some"|"none", viewStudents?: "all"|"some"|"none", studentFilterValues?: string[], // comma delimited list of values, such as "a, b, c, d" studentFilter?: string // Field on which students can be filtered visibleCohorts?: string[], // comma delimited list of values readUpdates?: string[], contactProviderConsent?: boolean, contactProviderConsentDate?: boolean referrals?: number, shareNameWithReferralLeaderboardConsent?: boolean, shareNameWithReferralLeaderboardConsentDate?: boolean, referralCode?: string, notificationFrequency?: "daily"|"weekly"|"fortnightly"|"never", monthAdded?: number, placementsCharged?: boolean, visibleAddresses?: string[], visibleSchools?: string[], viewSchoolGroups?: "all"|"none"|"some", // For careers hubs visibleSchoolGroups?: string[], // For careers hubs visibleListings?: string[], requestedVisibleAddresses?: string[], requestedVisibleListings?: string[], packageData?: BillingPackage, viewAddresses?: "all"|"request"|"none"|"some", viewSchools?: "all"|"request"|"none"|"some", viewPlacementListings?: "all"|"request"|"none", viewPlacementGroups?: "all"|"request"|"none", skillsTargets?: string[], skillsTargetsValues?: {[key: string]: { provider: number[], student: number[], }}, alumniConversationUid?: string, savedDataViewerFilters?: { [cohortId: string]: { [key in "cohortPlacements"|"cohortStudents"]: { [viewKey: string]: DataViewerFilterView } } }, hasReservedListings?: boolean, reservedListings?: { expiryDate: string, listingId: string }[], calendarIntegration?: { secret: string, // random code active?: boolean, integrations: ("placementReminders"|"draftEvents"|"publishedEvents"|"employerEmails"|"placementDates")[] created: Timestamp, lastSynced: Timestamp, }, completedProductFeedback?: string[], notes?: Descendant[], // NOTE Student Statistics placements?: number, scheduledHours?: number, scheduledEvents?: number, completedHours?: number, completedEvents?: number, completedHoursPerActivity?: {[activityId: string]: number} completedHoursPerBenchmark?: {[benchmarkNumber: number]: number} completedEventsPerActivity?: {[activityId: string]: number} completedEventsPerBenchmark?: {[benchmarkNumber: number]: number} scheduledHoursPerActivity?: {[activityId: string]: number} scheduledHoursPerBenchmark?: {[benchmarkNumber: number]: number} scheduledEventsPerActivity?: {[activityId: string]: number} scheduledEventsPerBenchmark?: {[benchmarkNumber: number]: number}, additionalNeeds?: string, }; export type DataViewerFilterView = { title: string, search?: string, sort?: string, filters?: FilterObject, permanent?: boolean, } export type AnalyticsItem = { units?: "placements"|"weeks"|"days"|"hours", name?: string total?: number, completion?: { total?: number, completed?: number }, time?: {[key: string]: {date?:string, total?: number, completion?: {total?: number, completed?:number}}}, year?: {[key: string]: {year?: number, total?: number, completion?: {total?: number, completed?:number}}}, subtypes?: {[key:string]: AnalyticsItem} } export type UserGroupData = { id: string, default?: boolean, name: string, template: "Staff"|"Students", oId: string, product: Products, viewStudents: "all"|"filter"|"none", filterUsersBy?: string, filterUsersValue?: string, }&ProviderUserPermissions export type StaffUserGroup = UserGroupData & StaffUserPermissions export type ProviderUserGroup = UserGroupData & ProviderUserPermissions export type StaffUserPermissions = UserGroupData & { viewStaff: boolean, addStaff?: boolean, activateStaff?: boolean, editStaff?: boolean, deleteStaff?: boolean, addStaffGroups?: boolean, editStaffGroups?: boolean, deleteStaffGroups?: boolean, addStudents?: boolean, activateStudents?: boolean, editStudents?: boolean, deleteStudents?: boolean, viewSetup?: boolean, editInstitute?: boolean, addForms?: boolean, editForms?: boolean, deleteForms?: boolean, addFiles?: boolean, deleteFiles?: boolean, viewBilling?: boolean, manageBilling?: boolean, proposePlacements?: boolean, createCohorts?: boolean, viewPlacements?: boolean, viewPlacementTasks?: boolean, signOffPlacements?: boolean, editPlacements?: boolean, addPlacements?: boolean, deletePlacements?: boolean, verifyInsurance?: boolean, verifyListings?: boolean viewDatabase?: boolean, addListings?: boolean, deleteListings?: boolean, verifyRiskAssessments?: boolean, verifyDbsChecks?: boolean, addCohorts?: boolean, editCohorts?: boolean, deleteCohorts?: boolean, editRequests?: boolean, deleteRequests?: boolean, addEmailTemplates?: boolean, editEmailTemplates?: boolean, deleteEmailTemplates?: boolean, addActivity?: boolean, editActivity?: boolean, deleteActivity?: boolean, readGuidance?: boolean, uploadGuidance?: boolean } export type ProviderUserPermissions = { viewStaff: boolean, addStaff?: boolean, activateStaff?: boolean, editStaff?: boolean, deleteStaff?: boolean, addUserGroups?: boolean, editUserGroups?: boolean, deleteUserGroups?: boolean, addStudents?: boolean, addForms?: boolean, editForms?: boolean, deleteForms?: boolean, addFiles?: boolean, deleteFiles?: boolean, viewBilling?: boolean, manageBilling?: boolean, createPlacementListing?: "any"|"template"|"none", createPlacementTemplate?: boolean, viewPlacementListings?: "all"|"request"|"none", viewPlacementGroups?: "all"|"request"|"none", viewAddresses?: "all"|"request"|"none", processApplicants?: boolean, addSchools?: boolean, editSchools?: boolean, deleteSchools?: boolean, addAddresses?: boolean, editAddresses?: boolean, deleteAddresses?: boolean, addApplicantWorkflows?: boolean, editApplicantWorkflows?: boolean, deleteApplicantWorkflows?: boolean, editRequests?: boolean, deleteRequests?: boolean, manageAccessRequests?: boolean, manageRegistrationRequests?: boolean, } export type RegistrationRequest = { forename: string, surname: string, email: string, message: string, created: string, oId: string, product: "providers"|"institutes" } export type WorkflowStage = { id: number, name: string, description?: string, permanent?: boolean, checkpoint?: boolean, buttons?: {id: number, name: string|false, description?: string, required: boolean}[], pos?: { x: number, y: number }, userType?: "Students" | "Staff" | "Provider" | "Parent", forms?: string[], files?: string[], deadline?: string, deadlineType?: "date"|"days" formDetails?: [{name: string}], eli?: boolean, riskAssessment?: boolean, dbsCheck?: boolean, defaultForms?: { name: string, description: string, time: "during"|"post", user: "staff"|"students"|"provider", details: CustomFormSchema }[], requiredFiles?: {fileName: string, fileType: string}[] }; export type ProviderPlacementData = { title: string, name: string, providerPhone: string, providerEmail: string, contactForename: string, contactSurname: string, providerId: string, addressId: string, sector: string, subsector: string, businessSize: string, id?: string }; export type ProviderData = { // staff: number, // staffFields: string[], // staffActive: number, // admin: string, name: string, // insurance: boolean|"awaitingReview", // insuranceSkippedReason?: string, regNumber?: string, // insuranceExpiry: string, // mapConsent?: boolean|"unlisted", // mapConsentDate?: string, // staffGuidance?: {[key:number]: string}, // about?: string, sector: string, // defAddress: string, subsector: string, businessSize: string, website?: string, created?: string uploadedBy?: "institute"|"provider"|"student" // onboarding?: { // hasStaff?: boolean, // multipleAddresses?: boolean, // } // registrationRequests?: boolean|string, // registrationRequestsDate?: string, // information: { // description?: string, // staff?: string, // locations?: number, // }, // discount?: string, // package: string, // splitBilling?: boolean, // adminBillingContactId: string, // addOnPackages?: string[], }&Address export type ProviderContactData = { sector: string, name: string, subsector: string, businessSize: string, providerPhone?: string, providerEmail: string, contactForename: string, contactSurname: string, website?: string, uid?: string created: string, providerId: string, insurance: boolean|"awaitingReview", insuranceSkippedReason?: string, insuranceExpiry?: string, accessCode?: string, accessExpiry?: string, savedBy?: {[key:string]: { exists: true, activities?: null|string[], // IDs of consented activities. eventsConsent?: boolean, eventsConsentDate?: string, providerConsent?: boolean, // Actually consent to placemnts. providerConsentDate?: string, MATschools?: string[], notes?: Descendant[], status: "uploaded"|"approved"|"rejected"|"providerReviewed"|"blocked"}}, }&Address export type InstituteData = { students: number, staff: number, studentsFields: string[], staffFields: string[], studentsActive: number, staffActive: number, admin: string, name: string, monthAdded: number, platformFee: number, color?: string, verifiedProviders?: string[], awaitingProviderInsurance?: string[], verifiedRiskAssessments?: string[], awaitingPlacementRiskAssessments?: string[], verifiedDbsChecks?: string[], awaitingPlacementDbsChecks?: string[], staffGuidance?: {[key:number]: string} studentsGuidance?: {[key:number]: string}, cohortRequests: {[oId: string]: {[cohortId: string]: string[]}}, acceptingEventRequests?: boolean, approveEventRequests?: boolean, acceptingEmployers?: boolean, publicEventPage?: boolean, discount?: string, package: string, careersHubLinks?: {[oId: string]: { exists: boolean, invited: string, status: "invited"|"approved"|"declined", schoolGroups?: string[], notes?: Descendant[], emailsSent?: { sent?: Timestamp, log: { [k: string]: string // dateTimeString : eventType } topInteraction: "sent"|"bounced"|"delivered"|"opened"|"clicked", messageId?: string, }[] }}, trustLinks?: {[oId: string]: { exists: boolean, invited: string, status: "invited"|"approved"|"declined", }}, wonde?: { hasIntegration: boolean, createdDate: Timestamp, lastSynced: Timestamp, id: string, connectionToken: string, fields?: string[] }, emailDomain: string, splitBilling?: boolean, adminBillingContactId?: string, // Packages institutes can be signed up to employerEvents?: boolean, workExperience?: boolean, alumniManagement?: boolean, // ------------------------ authorisedMISSystem?: { name: "arbor", data: { url: string } }, acceptingAlumni?: boolean, approveAlumni?: boolean, shareAlumni?: boolean approveAlumniMessages?: boolean, anonymiseAlumniConvoStudents?: boolean, alumniConversations?: boolean, activityInvitesSent?: string, schoolCanViewEmployerEmail?: boolean, defaultEventFeedbackForms?: { students?: string, staff?: string, parent?: string, provider?: string, school?: string, } defaultPlacementFeedbackForms?: { students?: string, staff?: string, parent?: string, provider?: string, } }&Address; export type ExternalActivity = { title?: string, description: string, position?: number, tag?: "wex", type?: "careersHub"|"school", image?: string, color: string, public?: boolean, oId?: string, alumni?: boolean, provider?: boolean, permanent?: boolean, activityType: "workExperience"|"workplaceVisits"|"mentoring"|"mockInterviews"|"other" } export type NotificationObject = { buttonURL: string, created: Timestamp, description: string, title: string, viewableBy: string[], viewedBy: string[], docPath: DocumentReference } export type CustomFormSchemaField = { id: number, label: string, required: boolean, type: "short"|"long"|"number"|"date"|"dropdown"|"checkbox"|"rating" // If Microsoft forms has more, make a note and I'll add them width: number, // 1-12 default 12 subtitle?: string, extra: { default?: boolean /* type: checkbox */ | string /* type: short, long, dropdown (inputted option) */ | number /* type:number */, min?: number /* type: number */ max?: number /* type: number */ minRows?: number /* type: long */ options?: string[] // from dropdown only levels?: number // For ratings, number of stars. } } export type CustomFormSchemaSection = { id: number // random title?: string, description?: string, fields: CustomFormSchemaField[] } export type CustomFormSchema = { name?: string, description?: string, updated?: string, id?: string, oId?: string, form?: CustomFormSchemaSection[]} export type StaffRoles = { name: string, filters: { students: string[], fields: {[key:string]: unknown}, }, staff: string[] }; export type QueryObjectConstraint = [string, "=="|"<"|"<="|">="|">"|"!="|"array-contains"|"array-contains-any"|"in"|"not-in", string|boolean|string[]] export type QueryObject = { path: string[], where?: QueryObjectConstraint[], orderBy?: string }; export type Note = { title?: string, body?: { type: string; children: { text: string; }[]; }[], created: string, updated: string } export type Referral = { signUps: number, volume: number, product: Products, expiry: Timestamp, name: string } export type Contact = { id: string, contactForename: string, contactSurname: string, name: string, providerEmail: string, providerPhone: number, "address-line1": string, "address-line2": string, locality: string, what3Words?: string, postal_code: string, country: string, created: string, docPath: unknown } export type CohortData = { id?: string, name: string, placementType: "defined"|"continuous", forms?: string[], files?: string[], startSubmission: string, endSubmission: string, startPlacements: string, endPlacements: string, stage: "info"|"name"|"placementType"|"students"|"workflow"|"review"|"created"|"archived"|"database", workflow: WorkflowStage[] customWorkflow?: boolean, oId: string, product: Products, schoolId?: string, designatedStaff?: string, autoArchiveDate?: string, logType?: "basic"|"custom", listingReleaseDate?: string, enableListings?: boolean, shareEmployerFeedback?: boolean, logs?: { students?: string, staff?: string, provider?: string, } feedback?: { students?: string|false, staff?: string|false, parent?: string|false, provider?: string|false, }, feedbackText?: { students?: Descendant[], staff?: Descendant[], parent?: Descendant[], provider?: Descendant[], }, emailTemplates?: {[key in keyof typeof emailTemplates]: string}, skillsTargets?: string[], recurringEmails?: { sendType?: "all"|"lastWeek", frequency?: "oneTime"|"weeklyMonday"|"fortnightlyMonday" }, savedDataViewerFilters?: { [key in "cohortPlacements"|"cohortStudents"]: { [key: string]: DataViewerFilterView } }, userFilters?: { allSelected: boolean; search: string | undefined; filters: [string, unknown][] | undefined; } } export type ArrowObject = { start: number|string, end: number|string, name: string|false, description?: string, required?: boolean, screenX?: number, } export type AggregatedFeedback = { // Has same ID as cohort or event. students?: { [key: string/** key is formID_fieldID */] : {[key: string]: string[]}|string[], /**key is: number for rating; string for dropdown value, number for number value, boolean for checkbox, dbstring for date; */ completed: string[], }, staff?: { [key: string/** key is formID_fieldID */] : {[key: string]: string[]}|string[], /**key is: number for rating; string for dropdown value, number for number value, boolean for checkbox, dbstring for date; */ completed: string[], }, parent?: { [key: string/** key is formID_fieldID */] : {[key: string]: string[]}|string[], /**key is: number for rating; string for dropdown value, number for number value, boolean for checkbox, dbstring for date; */ completed: string[], }, provider?: { [key: string/** key is formID_fieldID */] : {[key: string]: string[]}|string[], /**key is: number for rating; string for dropdown value, number for number value, boolean for checkbox, dbstring for date; */ completed: string[], }, school?: { [key: string/** key is formID_fieldID */] : {[key: string]: string[]}|string[], /**key is: number for rating; string for dropdown value, number for number value, boolean for checkbox, dbstring for date; */ completed: string[], }, oId: string } export type PlacementReviewDetails = { activeDates: string[], studentForename: string, studentSurname: string, instituteName: string, completedStages: number[], title: string, product: string, name: string, startDate: string, endDate: string, providerEmail: string, providerPhone: string, contactForename: string, contactSurname: string, cohort: string, cohortData?: CohortData, providerKey: string, status: number, ["address-line1"]: string, ["address-line2"]: string, locality: string, postal_code: string, what3Words?: string, country: string, key: string, oId: string, workingHours: { [date: string]: [string, string]; }; providerCompleted: string[], providerId: string, questions: PlacementQuestions, userType: string, id: string, uid: string, leadTimes: string[], requiredSections: string[], existingPlacements?: { [key: string]: { mapConsent: boolean, jobTitle: string, questions: PlacementQuestions, riskAssessment: boolean|"awaitingReview", riskAssessmentType: "form"|"file", riskAssessmentData?: {[key: string]: unknown}|string, dbsCheck: boolean|"awaitingReview", dbsCheckType: "form"|"file", dbsCheckData?: {[key: string]: unknown}|string, } }, requireELI?: boolean, requireRA?: boolean, requireDBS?: boolean, importedProviderForms: boolean, currentStage: WorkflowStage&{files: {[fileId: string]: {name: string, url: string}}}, placementId?: string, providerContactId: string, incompleteItems: {[key: number]: string[]}, riskAssessmentData?: {[key: string]: unknown}[]|string, dbsCheckData?: {[key: string]: unknown}[]|string, feedbackText?: Descendant[], feedback: CustomFormSchema, feedbackData?: {[key: string]: unknown}, primaryColor?: string, primaryImage?: string, mapConsent?: boolean, eventsConsent?: boolean, consentedActivities?: string[], instituteActivities?: {[key: string]: ExternalActivity} } export type BlogCategories = "students"|"providers"|"institutes"|"careerthread" export type Blog = { title?: string, summary?: string, body?: Descendant[], uploaded?: string, category?: BlogCategories, author?: string, tags?: string } export type PlacementExportObject = { cohortId: string, startDate?: string, endDate?: string, allTime?: boolean, includeStudentData?: boolean, activePlacements?: boolean, completedPlacements?: boolean, } export type ApplicantWorkflow = { id?: string, name: string, forms?: string[], files?: string[], workflow: ApplicantStage[] customWorkflow?: boolean, oId: string, product: Products, type: "simple"|"complex" } export type ApplicantStage = { id: number, name: string, message?: string, userType?: "Students" | "Staff", permanent?: boolean, checkpoint?: boolean, buttons?: {id: number, name: string|false, required: boolean}[], pos?: { x: number, y: number }, forms?: string[], files?: string[], deadline?: string, deadlineType?: "date"|"days" formDetails?: {[key: string]: { name: string, id: string, description?: string, product: Products, oId: string, form: CustomFormSchema }}, requiredFiles?: {fileName: string, fileType: string}[] portfolio?: boolean, viewableFiles?: {[key: string]: FileItem}, }; export type Application = { id?: string, uid: string, applicantWorkflowId: string, listingId: string, addressId: string, providerId: string, reqUserType: "Students"|"Staff", completedSections: {[stage: number]: { submitted?: string, filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string[]}, }}, created: string, submitted: string, startDate: string, endDate: string, leadTimes?: string[], stage: number, // This is what stage of the custom workflow. outcomeMessage?: string, status: "draft"|"submitted"|"approved"|"declined", placementId?: string, } export type Report = { added: string, id: string, oId: string, product: Products, pId: string, reason: string, uid: string, status: "open"|"closed" } export type FileItem = { product: Products, oId: string, added: string, name: string, fileName: string, url?: string, uploadedBy?: "employer", pId?: string, } export type GuidanceItem = FileItem&{ visibility: "students"|"parents"|"employers"|"staff", recommendation: ("onceActivated"|"placementCreated"|"weekBeforePlacement"|"placementStarted"|"placementFinished")[], public?: boolean, type: "guidance" } export type Event = { collection: "users"|"placements"|"placementListings", documentId: string, product: Products, oId: string, created: Timestamp, title: string, description?: string, severity: string, button?: {title: string, url: string} } export type BillingPackage = { name: string, staffUnitCost: number, platformFee: number, platformFeeFrequency: "yearly"|"monthly", studentUnitCost: number, placementUnitCost: number, product: Products, priority: number, features: {[key: string]: number|boolean|string}, description: string } export type EmailTemplate = { name: string, created: Timestamp, subject: string, emailTemplate: string, bodyText: Descendant[], color?: string, product: Products, oId: string, public?: boolean, selectable?: boolean, campaign?: boolean, } export type EmailTemplateConfig = { description: string, params: string[], button?: {text: string, link: string}, type: "workflow"|"feedback"|"event"|"campaign" } export type EmailCampaign = { id: string, oId: string, schoolId?: string, type: "employer"|"alumni", title: string, description?: string, created: string, emailTemplateId?: string, draft: boolean, sendTime?: string, status: "draft"|"sending"|"sent", stage:"basicDetails"|"recipients"|"emailContent"|"scheduling"|"review"|"awaitingSend"|"sending"|"sent" designatedStaff?: string recipientIDs?: string[] // List of recipient IDs recipients: { allSelected: boolean; search: string | undefined; filters: {k: string, e: WhereFilterOp, v: unknown}[] | undefined; }|(string|{[key: string]: unknown})[] // Filters or list of recipients } export type EmailCampaignRecipient = { oId: string, campaignId?: string, created: string, contactId: string, type: "alumni"|"employer" sent: string, // ISO string messageId?: string, topInteraction: "invalid_email"|"hard_bounce"|"soft_bounce"|"blocked"|"error"|"deferred"|"unsubscribed"|"click"|"unique_opened"|"delivered"|"request"|"sent", log: { [k: string]: string // dateTimeString : eventType } interactions?: string[] } export type Reminder = { collection: "users"|"placements"|"placementListings", documentId: string, product: Products, oId: string, created: Timestamp, title: string, description?: string, dueDate: string, status: "upcoming"|"dismissed" } export type ProductFeedback = { formId: string, title: string, description: string, product: Products, userType: "Staff"|"Students", userGroup: "admin"|"all", created: string, released: string // iso string published?: boolean, } export type Sorts = {[label: string]: { value: string direction: "asc"|"desc" }}|undefined export type SchoolData = OrganisationAddress&{ billingEmail?: string, billingContactId?: string, authorisedMISSystem?: { name: "arbor", data: { url: string } }, wonde?: { hasIntegration: boolean, createdDate: Date, lastSynced: Date, id: string connectionToken: string, fields?: string[] }, monthAdded: number, acceptingAlumni?: boolean, approveAlumni?: boolean, shareAlumni?: boolean, approveAlumniMessages?: boolean, anonymiseAlumniConvoStudents?: boolean, alumniConversations?: boolean, acceptingEventRequests?: boolean, acceptingEmployers?: boolean, careersHubLinks?: {[oId: string]: { exists: boolean, invited: string, status: "invited"|"approved"|"declined", schoolGroups?: string[], emailsSent?: { sent?: Timestamp, log: { [k: string]: string // dateTimeString : eventType } topInteraction: "sent"|"bounced"|"delivered"|"opened"|"clicked", messageId?: string, }[] }}, } // SchoolGroup is a group that schools can be assigned to by a Careers Hub export type SchoolGroup = { name: string, careersHubId: string, } export type ExternalEvent = { name: string, description: string, staffInformation?: string, studentInformation?: string, schoolInformation?: string, employerInformation?: string designatedStaff: string, designatedStaffText: string, eventRequestId?: string, equalexLearningOutcomes?: string, created: string, activityId?: string, visibleTo: string[] // All institutes that can see this event. E.g. Careers Hubs and schools gatsbyBenchmarks?: number[], // String array oId: string, submissionClose: string, acceptingEmployers?: boolean, acceptingStudents?: boolean, acceptingSchools?: boolean, schoolId?: string, yearGroups?: string[], // Dates whoDecidesDates?: "staff"|"student"|"employer"|"school", dateSelectionType?: "single-day"|"multi-day", startDate?: string, endDate?: string, treatRecurrencesIndependently?: boolean, startTime?: string, endTime?: string, allDay?: boolean, recurring?: boolean, recurringFrequency: "daily"|"weekly"|"fortnightly"|"monthlyOnDate", recurringUntil?: number, // ---------------------- targetStudents?: number, // Target number of students targetSchools?: number, // Target number of schools maxExternalAttendees?: number, // max number of employers maxSchools?: number, // max number of employers maxStudents?: number, // max number of employers stage: "basicDetails"|"eventConfig"|"selectEmployers"|"employerInviteForms"|"sendEmployerInvites"|"setupStudentInvites"|"preEvent"|"created", draft: boolean, inviteEmailTemplate: string, employerConfirmationEmailTemplate: string, employerCapacity?: boolean, totalCapacity?: number, targetEmployers?: number, eventConfigStage?: string, studentHours?: number, skipEmployerInvites?: boolean, alumni: { completed?: boolean, shareable?: boolean, filters: { allSelected: boolean; search?: string; filters?: {k: string, e: WhereFilterOp, v: unknown}[]; }|(string|{[key: string]: unknown})[] } employers: { stage: "selectEmployers"|"employerInviteForms"|"sendEmployerInvites", completed?: boolean, shareable?: boolean, filters: { allSelected: boolean; search?: string; filters?: {k: string, e: WhereFilterOp, v: unknown}[]; source: "institute"|"hub"; }|(string|{[key: string]: unknown})[], public: boolean, }, studentInvites?: { completed?: boolean, link?: boolean, matchStudents?: boolean|"multiple", studentsMatchSelves?: boolean, files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], }, schoolInvites?: { completed?: boolean, link?: boolean, matchSchools?: boolean|"multiple", schoolsMatchSelves?: boolean, files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], }, employerInvites: { completed?: boolean files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], }, employerFeedback?: { files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], }, studentFeedback?: { files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], } schoolFeedback?: { files: string[], forms: string[], requiredFiles: { fileName: string, fileType: string }[], }, duringEvent?: {[key in "studentPre"|"employerPre"|"studentDuring"|"schoolPre"|"schoolDuring"|"schoolPost"|"employerDuring"|"studentPost"|"employerPost"]: { forms?: {form: string, relatedToUpload?: string, visibleTo?: ("employers"|"students"|"parents"|"school")[]}[], files?: string[], requiredFiles?: {fileName: string, fileType: string, visibleTo?: ("employers"|"students"|"parents"|"school")[]}[], deadline?: string, exists?: boolean, }}, feedback?: { students?: string|false, staff?: string|false, parent?: string|false, provider?: string|false, school?: string|false, }, completedStages: ("basicDetails"|"eventConfig"|"selectEmployers"|"employerInviteForms"|"sendEmployerInvites"|"setupStudentInvites"|"setupSchoolInvites"|"review"|"created"|"launched")[] }&Address export type ExternalEventRequest = { id: string, title?: string, description?: string, type: "withSchool"|"independent", webLink?: string, year?: string[], requestedBy: "employer"|"school", email?: string, created: string, consent: boolean, files?: FileList, numStudents?: number, oId: string, instituteId?: string, // School requesting it. providerContactId?: string, providerId?: string, dates?: {startDate: string, endDate?: string}[], events?: string[], // All the IDs of the events linked with this. Could be from multiple schools availableInteractions?: number, // How many events could be created from this request? status: "pending"|"pendingInstitute"|"sentToSchools"|"linkedWithEvent"|"declined", schoolSelectionType?: "allSchools"|"selectGroups"|"specificSchools", schools?: string[], schoolGroups?: string[], numberSharedWith?: number, maxSchools?: number, viewedBy?: {[key: string]: boolean}, downloadedBy?: {[key: string]: boolean}, } export type Alumni = { forename: string, surname: string, email: string, startYear: string, endYear: string, activities: string[], oId: string, schoolId?: string, dateAdded?: string, currentEnrolment: "university"|"apprenticeship"|"employment", status: "inactive"|"awaitingStaff"|"active" sector: string, subsector: string, businessSize: string, enrolmentHistory: {}[], visibleToStudents?: boolean, enableConversations?: boolean, linkCode: string, linkCodeExpiry: string } export type AlumniConversation = { alumniId: string, externalStudentId: string, alumniSharable?: boolean, oId: string, schoolId?: string, studentSharable?: boolean, messages: {[key: string]: { sentBy: "alumni"|"student", sentAt: string, message: string, delivered: "blocked"|"pending"|true, }}, open: boolean, reported?: boolean, delivered: "blocked"|"pending"|true, report?: { reportedBy: "alumni"|"student" message: string, createdDateTime: string, resolvedDateTime: string, } } export type AlumniConvoUser = { forename: string, surname: string, email: string, dateAdded: string, oId: string, schoolId?: string, linkCode: string, linkCodeExpiry: string } export type Update = { title: string, description: Descendant[], userType: "Staff"|"Students", product: Products, buttonText?: string, buttonLink?: string, date: string, imageData?: boolean } export type ExternalEventAttendee = { oId: string, schoolId?: string, eventId: string, providerContactId: string, finished?: boolean, students?: string[], schools?: {[key: string]: number}, // NOTE ID with number of students capacity?: number, created: string, eventDates?: { startDate: string, endDate: string, }, yearGroups?: string[], activityId?: string, gatsbyBenchmarks?: number[], // String array equalexLearningOutcomes?: string, dates?: { startDate: string, endDate?: string, }[], proposedDates?: { startDate: string, endDate?: string, }[], status: "pendingInvite"|"invited"|"requestedDates"|"providerAvailable"|"finalConfirmationSent"|"providerConfirmed"|"feedbackSent" emails: { [k in "invited"|"finalConfirmationSent"|"feedbackSent"]: { sent: number, // If below 3, keep sending reminders. reconciled: string|boolean, // When did the step get finished, such as employers responding to invites log: { [k: string]: string // dateTimeString : eventType } topInteraction: "invalid_email"|"hard_bounce"|"soft_bounce"|"blocked"|"error"|"deferred"|"unsubscribed"|"click"|"unique_opened"|"delivered"|"request"|"sent", messageId?: string, interactions?: string[] } } noInvite?: boolean, initialJobId?: string, emailTemplates?: { invited?: string, finalConfirmationSent?: string, feedbackSent?: string, } completedInvite: { filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string}, accepted?: boolean|string, }, completed: {[key in "employerPre"|"employerDuring"|"employerPost"]: { filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string}, accepted?: boolean|string, }}[], attended?: boolean, feedback: { provider: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp } }, } export type ExternalEventCareersSchool = { oId: string, instituteId: string, eventId: string, status: "invited"|"available"|"finalConfirmationSent"|"confirmed"|"feedbackSent"|"declined"|"visibleTo"|"creator", employers?: {[key: string]: { dates?: { startDate: string, endDate?: string, }[] }}, eventDates?: { startDate: string, endDate: string, } yearGroups?: string[], activityId?: string, gatsbyBenchmarks?: number[], // String array equalexLearningOutcomes?: string, created: string, finished?: boolean, visibleTo: string[], emails: { [k in "invited"|"finalConfirmationSent"|"feedbackSent"]: { sent: number, // If below 3, keep sending reminders. reconciled: string|boolean, // When did the step get finished, such as employers responding to invites log: { [k: string]: string // dateTimeString : eventType } topInteraction: "sent"|"bounced"|"delivered"|"opened"|"clicked", messageId?: string, } } completed: {[key in "schoolPre"|"schoolDuring"|"schoolPost"]: { filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string}, accepted?: boolean|string, }}[], initialJobId?: string, emailTemplates?: { invited?: string, finalConfirmationSent?: string, feedbackSent?: string, } inviteDocs?: {[key: string]: unknown} attended?: boolean, feedbackDocs?: {[key: string]: unknown} dates?: { startDate: string, endDate?: string, }[] proposedDates?: { startDate: string, endDate?: string, }[], feedback: { students: { data?: {[key: string]: {[key: string]: unknown}}, sent?: Timestamp }, parent: { completed: boolean, data?: {[key: string]: {[key: string]: unknown}}, sent?: Timestamp }, provider: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, school: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, }, } export type ExternalEventStudent = { oId: string, uid: string, schoolId?: string, finished?: boolean, eventId: string, status: "invited"|"joined"|"confirmed"|"removed", created: string, joined?: string, yearGroups?: string[], activityId?: string, gatsbyBenchmarks?: number[], // String array equalexLearningOutcomes?: string, studentHours?: number, eventDates?: { startDate: string, endDate: string, } visibleTo?: string[], emailTemplates?: { invited?: string, finalConfirmationSent?: string, feedbackSent?: string, } completed: {[key in "studentPre"|"studentDuring"|"studentPost"]: { filesViewed?: string[], formsCompleted?: {[key: string]: unknown}, filesUploaded?: {[key: number]: string}, accepted?: boolean|string, }}[], employers?: string[], attended?: boolean, dates?: { startDate: string, endDate?: string, }[], proposedDates?: { startDate: string, endDate?: string, }[], feedback: { students: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, parent: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, provider: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, staff: { completed: boolean, data?: {[key: string]: unknown}, sent?: Timestamp }, }, } export type CareersHubInvite = { careersHub: string, email: string, forename: string, surname: string, schoolName: string, invited: string, status: "invited"|"approved"|"declined", schoolGroups?: string[], emailsSent?: { sent?: Timestamp, log: { [k: string]: string // dateTimeString : eventType } topInteraction: "sent"|"bounced"|"delivered"|"opened"|"clicked", messageId?: string, }[] } export type TrustInvite = { trust: string, email: string, forename: string, surname: string, schoolName: string, invited: string, status: "invited"|"approved"|"declined", schoolGroups?: string[], emailsSent?: { sent?: Timestamp, log: { [k: string]: string // dateTimeString : eventType } topInteraction: "sent"|"bounced"|"delivered"|"opened"|"clicked", messageId?: string, }[] } // For backend emails export type EmailContentObject = { subject: string, preheader: string, salutation?: string, title: string, body: string|Descendant[], primaryButton?: { title: string, url: string, }, secondaryButton?: { title: string, url: string, }, viewableBy?: string[], designatedStaffEmail?: string, primaryColor?: string, organisationName?: string; params?: EmailTemplateConfig; data?: { [key: string]: string|undefined; }; primaryImage?: string, } export type YearScoreData = { eventsInvited?: number, eventsFinished?: number, eventReplied?: number, feedbackGiven?: number, eventRequests?: number, campaignsSent?: number, campaignsOpened?: number, campaignsClicked?: number, campaignsFailed?: number, } type MessageTypes = "hubOrTrustInviteSchool" | "sendPlacementActionRequired" | "sendPlacementAdditionalInformationRequired" | "sendFeedbackReminder" | "sendProviderContactInvite" | "sendProviderContactActivityInvite" | "sendActivateUserAccount" | "shareEmployerEventRequest" | "employerEventInvite" | "schoolEventInvite" | "reuploadPlacementDocument" | "requestEventDates" export type EmailInteraction = { messageId: string, collectionLink: string, collectionItemId: string, recipientId?: string, sent?: Timestamp, visibleTo: string[], title: string, log: { [k: string]: string // dateTimeString : eventType } topInteraction: "invalid_email"|"hard_bounce"|"soft_bounce"|"blocked"|"error"|"deferred"|"unsubscribed"|"click"|"unique_opened"|"delivered"|"request"|"sent", body: EmailContentObject, templateId?: string, interactions?: string[], recipientEmail: string, recipientForename: string, recipientSurname: string, // Email reminders values messageType?: MessageTypes, // This will be used to determine which test is necessary to decide to send a reminder reminderNumber?: number, // Which of the reminders is this? sendReminders?: boolean, sentDay: string, // Used to ensure we send >= 7 days before sent. additionalData?: {[key: string]: unknown} // Values to be used in the reminderChecker function } export type SkillLabel = { label: string, description: string, category: keyof typeof skillLabelColours, public: boolean, }