{"version":3,"sources":["modules/globals.ts","modules/logging.ts","modules/show-alert.ts","modules/rfc7807-problem.ts","modules/cupid-fetch.ts","modules/data-objects/subject.ts","modules/utils.ts","components/authentication/login-page.tsx","components/authentication/reviewer-login.tsx","components/app/nav.tsx","components/app/layout.tsx","modules/data-objects/sys-info.ts","components/utils/alert-box.tsx","modules/current-date.ts","modules/date-without-time.ts","modules/data-objects/activity.ts","components/edit-cpd/event-session-code.tsx","components/edit-cpd/attachment-list.tsx","components/edit-cpd/attachment-lists.tsx","components/edit-cpd/file-upload.tsx","components/utils/date-input.tsx","components/edit-cpd/main-input-fields.tsx","components/utils/logged-in-as.tsx","components/edit-cpd/edit-cpd.tsx","components/add-or-edit-cpd.tsx","modules/data-objects/activity-note.ts","components/activity-list/note-details.tsx","modules/data-objects/date-utils.ts","components/activity-list/activity-note-list.tsx","components/activity-list/activity-details.tsx","components/utils/cupid-slidedown.tsx","components/activity-list/activity-list-row.tsx","components/activity-list/activity-list-view.tsx","modules/data-objects/review-grant.ts","components/target-progress/progress-gauge.tsx","components/target-progress/progress-widget.tsx","components/activity-list/reviewer-activity-list.tsx","components/activity-list/activity-list.tsx","components/activity-list/activity-list-page.tsx","components/review-grant/view-grant.tsx","components/review-grant/edit-grant.tsx","components/review-grant/review-grant-row.tsx","components/review-grant/review-grant-page.tsx","components/targets.tsx","components/user-details.tsx","components/activity-list/draft-activity-list.tsx","components/app/home.tsx","components/app/app-config-cpd.tsx","components/committees/browse.tsx","components/app/app-config-committees.tsx","components/app/app.tsx","serviceWorker.ts","index.tsx","IHEEM-logo.png"],"names":["_globals","getGlobal","type","name","undefined","LoggingGlobals","errorLogger","console","error","getLoggingGlobals","logError","message","optionalParams","windowConfirm","Promise","resolve","window","confirm","windowAlert","alert","AlertGlobals","showAlert","showConfirm","getAlertGlobals","parseProblem","contentType","responseText","s","trim","i","indexOf","substr","parseContentTypeHeader","problem","JSON","parse","title","CupidFetchGlobals","prefix","fetchModule","fetch","bind","cupidFetch","cupidFetchImpl","getCupidFetchGlobals","url","a","method","payload","callShowAlert","response","body","stringify","globals","headers","text","status","get","Subject","obj","role","authenticated","Error","Object","assign","this","text_impact","nanToNull","numericValue","isNaN","encodeCurrentUrl","history","encodeURIComponent","location","pathname","search","State","waitingForServer","showInvalidUserNameError","userName","password","LoginPage","state","userNameOnChange","event","setState","target","value","passwordOnChange","loginButtonClick","isAuthenticated","props","loginCallback","loginButtonDisabled","resetPasswordLink","iheemWebSiteUrl","termsLink","privacyLink","className","onSubmit","e","preventDefault","appDescription","htmlFor","id","onChange","placeholder","data-testid","onClick","disabled","href","style","fontSize","rel","React","Component","ReviewerLogin","locaton","useLocation","token","URLSearchParams","useState","failed","setFailed","useEffect","authenticate","MenuState","Nav","subject","getNavEntries","smallScreen","useReactSimpleMatchMedia","Small","NotSmall","menuState","setMenuState","logout","hideMenu","SmallWithMenu","src","Logo","alt","map","o","key","to","icon","faUnlockAlt","Layout","renderLayoutRoutes","SysInfoGlobals","sysInfo","getSysInfoGlobals","getSysInfo","isConfirm","QueueEntry","promise","resolver","AlertBox","queue","queueEntry","find","r","push","length","addAlertToQueue","result","shift","buttonClicked","CurrentDateGlobals","getCurrentDate","Date","formatDateWithoutTimeForDisplay","date","format","parseDateWithoutTime","startOfYear","year","endOfYear","formatDateWithoutTime","Activity","activityId","userId","activityTypeId","activityDate","isEventSession","eventSessionCode","competencyRef","isCompleted","points","hours","expectedLearning","actualLearning","impact","comments","hasNotes","activityFromJson","activity","newActivity","activityIsEmpty","activityEquals","activity1","activity2","ignoreIsCompleted","_","isEqual","initialEventSessionCode","EventSessionCode","eventSessionCodeOnChange","dirtyCallback","onVerifyClick","clear","textContent","eventSessionMode","eventSessionModeVerify","normalModeVerify","prevProps","verifyEventSession","previousEventSession","existingActivity","newEventSession","eventSession","eventSessionSelected","verifiedCode","buttonLabel","buttonDisabled","display","maxLength","attachments","AttachmentList","mounted","onDeleteClick","attachmentId","attachment","fileName","refreshAttachmentList","anyAttachments","anyAttachmentsCallback","faCloudDownloadAlt","lastIndexOf","toLowerCase","reformatFileName","enableDelete","faTrash","eventSessionActivityId","AttachmentLists","getEventSessionActivityId","attachmentListNonce","file","lastSuccessfulFile","progress","request","extractFilename","path","x","FileUpload","formRef","createRef","fileUploadSuccess","fileUploadError","fileUploadComplete","fileUploadFailed","uploadInProgressCallback","getResponseHeader","fileSelectorChange","saveActivityCallback","current","dispatchEvent","Event","cancelable","fileUploadProgress","loaded","total","performUpload","formData","XMLHttpRequest","onload","onerror","upload","onprogress","open","send","cancelUpload","abort","FormData","showProgress","uploading","caption","ref","max","aria-label","aria-hidden","DateInput","form","required","min","validity","valid","MainInputFields","fieldOnChange","updates","updateFieldCallback","pointsOnChange","parseInt","hoursOnChange","parseFloat","activityDateOnChange","activityTypes","step","LoggedInAs","displayName","isCpdUser","membershipNo","isSysadmin","isReviewer","emailAddress","getDescription","lastSavedActivity","uploadInProgress","lastAutoSaveFailed","eventSessionCodeDirty","isCompletedOverride","_EditCpd","autoSaveTimer","firstSavePromise","isNew","isDirty","updateFields","isCompletedChange","selectedEventSession","extraUpdates","eventSessionCodeDirtyCallback","dirty","fileUploadSaveActivityCallback","saveActivity","inProgress","onCloseClick","goBack","saveOk","navigatedAway","interval","clientAppConfig","autoSaveInterval","setInterval","returnUrl","setAutoSaveTimer","fetchActivity","clearInterval","prevState","isAutoSave","urlSuffix","activityToSave","fieldsDisabled","buttonsDisabled","competencyRefLink","sessionCodeLink","checked","faCheckCircle","EditCpd","withRouter","_AddOrEditCpd","verifyEventSessionResult","savedActivity","AddOrEditCpd","ActivityNote","activityNoteId","reviewerName","reviewerEmail","noteDate","noteText","activityNoteFromJson","activityNote","valueOf","NoteDetails","dirtyNoteCallback","editMode","setEditMode","setNoteDate","setNoteText","setWaitingForServer","setActivityNoteId","editButtonVisible","acceptButtonVisible","deleteButtonVisible","acceptButtonEnabled","getUrl","suffix","onAcceptClick","newActivityNote","displayDateFormat","faPen","inverse","ActivityNoteList","activityNotes","setActivityNotes","isMounted","ActivityDetails","reloadActivityList","useHistory","activityType","deleteButtonClick","completeButtonClick","fetchedActivity","faTimesCircle","SlideDownGlobals","enableTransitions","CupidSlideDown","children","ActivityListRow","expanded","setExpanded","allowContract","setallowContract","isActive","faFileAlt","ActivityListView","activities","ReviewGrant","reviewGrantId","accessToken","expiryDate","activityStartDate","activityEndDate","reviewGrantFromJson","reviewGrant","newReviewGrant","getFullYear","gaugeWouldRender","actual","ProgressGauge","yearStart","yearEnd","totalDaysInYear","differenceInDays","daysSoFar","border","width","textAlign","percent","Math","arcsLength","colors","textColor","needleColor","formatTextValue","toFixed","float","marginTop","marginLeft","marginRight","ProgressWidget","targetPoints","setTargetPoints","targetHours","setTargetHours","actualPoints","setActualPoints","actualHours","setActualHours","setLoaded","selectedYear","userSuffix","toString","ReviewerActivityList","setActivities","reviewer","startDate","endDate","split","revieweeName","revieweeMewmbershipNo","ActivityList","loadActivityList","queryString","queryStringFromDateRange","queryStringFromYearRange","startYear","endYear","queryStringFromYear","ActivityListPage","nonce","setNonce","searchParams","startDateString","endDateString","selectedRange","yearSelectorValues","activityListConfig","activityList","yearRange","range","some","getYearSelectorValues","selectedEntry","faPlusCircle","size","oldValue","ViewGrant","startEditing","deleteGrant","sendNotification","msg","faEnvelope","EditGrant","cancelEdit","saveEdit","setReviewerEmail","setReviewerName","setexpiryDate","setActivityStartDate","setActivityEndDate","checkValidity","updated","ReviewGrantRow","initiallyExpanded","editing","setEditing","reviewGrants","newSaveId","_ReviewGrantPage","toSave","saveResult","loadReviewGrants","filter","createGrant","enableAdd","renderTableBody","ReviewGrantPage","Targets","setPoints","setHours","UserDetails","user","setUser","updatedUser","webFormName","renderRow","attrName","label","untypedUser","webFormAttrName","toUpperCase","slice","DraftActivityList","Home","appConfigCpd","renderNonLayoutRoutes","render","routeProps","match","params","getReturnUrl","redirectToLoginPage","encodePath","join","Browse","listFolderResult","setListFolderResult","folderEmpty","files","folders","segments","reduce","acc","cur","getBreadcrumbs","decodeURIComponent","tryToUrlDecode","faLevelUpAlt","faFolder","faFile","appConfigCommittees","App","setSubject","buildDate","setBuildDate","appConfig","app","getAppConfig","p1","p2","sessionResponse","getSubject","separator","Helmet","content","Boolean","hostname","ReactDOM","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister","catch","module","exports"],"mappings":"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","file":"static/js/main.c7875e76.chunk.js","sourcesContent":["/**\n * a module which stores global variables. each is expected to be an object \n * and is identified by a name.\n * if you ask for one that doesn't exist, it constructs it and stores it\n * before returning. You can then update the properties\n * Really this is intended as a dependency injection mechanism only used\n * for constructing test doubles. the idea is that the default constructor\n * for the class should set the production values, but the test runner can\n * override them if required.\n */\nlet _globals: any = {};\n\nexport function deleteGlobal(name:string) {\n delete _globals[name];\n}\n\nexport function clearAllGlobals() {\n _globals = {};\n}\n\nexport function getGlobal(type: { new(): T }, name: string): T {\n /*\n * this code inspired by https://stackoverflow.com/questions/17382143\n * I've no idea how it works\n */\n if (_globals[name] === undefined) {\n _globals[name] = new type();\n }\n return _globals[name] as T;\n}\n","import { getGlobal, deleteGlobal } from './globals';\n\nexport type ErrorLoggerType = (message?: any, ...optionalParams: any[]) => void;\n\nconst globalName = \"logging\";\n\nclass LoggingGlobals {\n errorLogger: ErrorLoggerType = console.error;\n}\n\nexport function getLoggingGlobals(): LoggingGlobals {\n return getGlobal(LoggingGlobals, globalName);\n}\n\nexport function resetLoggingGlobals(): void {\n deleteGlobal(globalName);\n}\n\nexport default function logError(message?: any, ...optionalParams: any[]): void {\n getLoggingGlobals().errorLogger(message, ...optionalParams);\n}\n","import { getGlobal, deleteGlobal } from './globals';\n\nexport type ShowAlertType = (message: string) => Promise;\nexport type ShowConfirmType = (message: string) => Promise;\n\nconst globalName = \"showAlert\";\n\nfunction windowConfirm(message: string) {\n return Promise.resolve(window.confirm(message))\n}\n\nfunction windowAlert(message: string) {\n return Promise.resolve(window.alert(message))\n}\n\nclass AlertGlobals {\n showAlert: ShowAlertType = windowAlert;\n showConfirm: ShowConfirmType = windowConfirm;\n}\n\nexport function getAlertGlobals(): AlertGlobals {\n return getGlobal(AlertGlobals, globalName);\n}\n\nexport function resetAlertGlobals(): void {\n deleteGlobal(globalName);\n}\n\nexport function showAlert(message: string): Promise {\n return getAlertGlobals().showAlert(message);\n}\n\nexport function showConfirm(message: string): Promise {\n return getAlertGlobals().showConfirm(message);\n}\n","export default function parseProblem(contentType: string | null, responseText:string) :string | null\n{\n if (parseContentTypeHeader(contentType) !== \"application/problem+json\") {\n return null;\n }\n const problem = JSON.parse(responseText) as ProblemDetails;\n return problem?.title ?? null;\n}\n\nfunction parseContentTypeHeader(contentType: string | null) : string {\n const s = (contentType ?? \"\").trim();\n const i = s.indexOf(\";\");\n if (i === -1) { \n return s;\n } else {\n return s.substr(0, i).trim();\n }\n}\n\nexport class ProblemDetails {\n title?: string | null;\n detail?: string | null;\n}\n","import { getGlobal } from './globals';\nimport logError from \"./logging\";\nimport { showAlert } from './show-alert';\nimport parseProblem from \"./rfc7807-problem\"\n\nexport type fetchType = (input: RequestInfo, init?: RequestInit) => Promise;\nexport type cupidFetchType = (url: string, method: string, payload: TPayload) => Promise;\n\nconst globalName = \"cupidFetch\";\n\nclass CupidFetchGlobals {\n prefix: string = \"\";\n fetchModule: fetchType = window.fetch.bind(window);\n cupidFetch: cupidFetchType = cupidFetchImpl;\n}\n\nexport function getCupidFetchGlobals(): CupidFetchGlobals {\n return getGlobal(CupidFetchGlobals, globalName);\n}\n\nexport default async function cupidFetch(url: string, method: string = \"GET\", payload?: TPayload): Promise {\n return await getCupidFetchGlobals().cupidFetch(url, method, payload);\n}\n\nfunction callShowAlert(s?: string | null) {\n const msg = s ?? \"Error communicating with server - see console for details\";\n showAlert(msg);\n}\n\nasync function cupidFetchImpl(url: string, method: string, payload?: TPayload): Promise {\n let response: Response | undefined = undefined;\n const body = (method === \"GET\" ? null : JSON.stringify(payload));\n const globals = getCupidFetchGlobals();\n\n try {\n response = await globals.fetchModule(globals.prefix + url, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body\n });\n } catch (ex) {\n logError(`Error occurred sending ${method} ${url}:`)\n logError(ex);\n callShowAlert();\n return null;\n }\n\n const responseText = await response.text();\n\n if (response.status !== 200 && response.status !== 204) {\n logError(`Unexpected response status ${response.status} from ${method} ${url}:`)\n logError(response)\n logError(responseText)\n let message: string | null\n if (response.status === 401) {\n message = \"You have been logged out due to inactivity. Please refresh and log in again\"\n } else {\n message = parseProblem(response.headers.get(\"content-type\"), responseText)\n }\n callShowAlert(message)\n return null\n }\n\n if (responseText === \"\") {\n return {} as TResult;\n }\n\n try {\n return JSON.parse(responseText);\n } catch (ex) {\n logError(`Error parsing JSON response from ${method} ${url}:`)\n logError(ex);\n logError(response)\n logError(responseText);\n callShowAlert();\n return null;\n }\n}\n\n\n","import ReviewGrant from \"./review-grant\"\n\nexport const ROLE_NOT_AUTHENTICATED = \"NOT_AUTHENTICATED\"\nexport const ROLE_CPDUSER = \"CPDUSER\"\nexport const ROLE_REVIEWER = \"REVIEWER\"\nexport const ROLE_SYSADMIN = \"SYSADMIN\"\n\nexport class SubjectDto {\n role?: string | null\n authenticated?: AuthenticatedUser | null\n}\n\nexport default class Subject {\n role!: string\n authenticated?: AuthenticatedUser | null\n\n constructor(obj: SubjectDto) {\n if (!obj || !obj.role) {\n throw new Error(\"You can't construct a subject with no role\")\n }\n Object.assign(this, obj)\n }\n\n isAuthenticated() {\n return this.role !== ROLE_NOT_AUTHENTICATED\n }\n\n isCpdUser() {\n return this.role === ROLE_CPDUSER\n }\n\n isSysadmin() {\n return this.role === ROLE_SYSADMIN\n }\n\n isReviewer() {\n return this.role === ROLE_REVIEWER\n }\n}\n\nexport class AuthenticatedUser {\n displayName?: string | null\n emailAddress?: string | null\n membershipNo? : string | null\n reviewer?: Reviewer | null\n}\n\nexport class Reviewer {\n reviewGrant!: ReviewGrant\n revieweeName!: string\n revieweeMewmbershipNo!: string\n}\n","import * as H from 'history';\n\nexport const unicode_no_break_space = \"\\u00a0\";\nexport const unicode_copyright_sign = \"\\u00a9\";\nexport const unicode_em_space = \"\\u2003\";\n\nexport const text_expected_learning = \"What did you expect to learn?\";\nexport const text_actual_learning = \"What did you learn?\";\nexport const text_impact = \"How do you see this impacting your work (next steps)?\";\nexport const text_comments = \"Any other comments?\";\n\nexport function nanToNull(numericValue: number) {\n return isNaN(numericValue) ? null : numericValue;\n}\n\nexport function encodeCurrentUrl(history: H.History) {\n return encodeURIComponent(history.location.pathname + history.location.search);\n}\n\n// returns s unless s is s1, in which case it returns s2\n// (a bit like null coalescing but with s1 instead of null)\nexport const substituteString = (s: string, s1: string, s2: string) => s === s1 ? s2 : s\n\nexport class BreadcrumbSegment {\n name!: string\n path!: string\n}\n\n/*\n * getBreadcrumbs splits the path into segments, each having a name and sub-path.\n * e.g. \"/a/b\" => [{ name: \"a\", path: \"/a/\" }, { name: \"b\", path: \"/a/b/\" }].\n * Leading and trailing slashes on the incoming path are ignored, as are double slashes.\n * returned paths have both leading and trailing slashes.\n * If the incoming path has only slashes, the output array is empty.\n */\nexport function getBreadcrumbs(s: string): BreadcrumbSegment[] {\n const segments = s.split(\"/\").filter(s => s)\n return segments.map((s, i) => {\n return {\n name: s,\n path: segments.slice(0, i + 1).reduce((acc, cur) => acc + cur + \"/\", \"/\")\n }\n })\n}\n","import React from 'react';\nimport cupidFetch from \"../../modules/cupid-fetch\";\nimport Subject, { SubjectDto } from '../../modules/data-objects/subject';\nimport { unicode_no_break_space } from '../../modules/utils';\nimport { iheemWebSiteUrl } from '../app/app';\n\nclass Props {\n loginCallback!: () => void\n appDescription!: string\n}\n\nclass State {\n waitingForServer: boolean = false;\n showInvalidUserNameError: boolean = false;\n userName: string = \"\";\n password: string = \"\";\n}\n\nexport interface LoginParams {\n userName?: string,\n password?: string,\n token?: string,\n}\n\nclass LoginPage extends React.Component {\n state: State = new State();\n\n userNameOnChange = (event: React.ChangeEvent) => {\n this.setState(\n { userName: event.target.value }\n );\n }\n\n passwordOnChange = (event: React.ChangeEvent) => {\n this.setState(\n { password: event.target.value }\n );\n }\n\n loginButtonClick = async () => {\n this.setState({ waitingForServer: true, showInvalidUserNameError: false });\n const response = await cupidFetch(\n '/api/session',\n 'POST',\n {\n userName: this.state.userName,\n password: this.state.password,\n }\n );\n this.setState({ waitingForServer: false });\n if (!response) return\n const subject = new Subject(response)\n if (!subject.isAuthenticated()) {\n this.setState({ showInvalidUserNameError: true })\n } else {\n this.props.loginCallback()\n }\n }\n\n render() {\n const loginButtonDisabled: boolean = (!this.state.userName) || (!this.state.password) || (this.state.waitingForServer);\n const resetPasswordLink = `${iheemWebSiteUrl}/wp-login.php?action=lostpassword`\n const termsLink = `${iheemWebSiteUrl}/terms-and-conditions/`\n const privacyLink = `${iheemWebSiteUrl}/privacy-policy/`\n return (\n <>\n
\n
\n
\n
e.preventDefault()}>\n

{this.props.appDescription} Login

\n \n {this.state.showInvalidUserNameError ? \"Invalid email/password\" : unicode_no_break_space}\n \n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n
\n
\n

What’s my password?

\n

\n To log into {this.props.appDescription}, use the same username and password as for the IHEEM Web site. If you have forgotten your password or don't have one, go to \n {resetPasswordLink}\n to set one, then return here to log in.\n

\n
\n
\n
\n
\n
\n
\n

 

\n

\n By logging into this site you agree to the terms and conditions at \n {termsLink}\n and the privacy policy at \n {privacyLink}\n .\n

\n
\n
\n
\n \n );\n }\n}\n\nexport default LoginPage;\n","import React, { useEffect, useState } from 'react'\nimport cupidFetch from \"../../modules/cupid-fetch\"\nimport Subject, { SubjectDto } from '../../modules/data-objects/subject'\nimport { useLocation } from 'react-router-dom'\nimport { LoginParams } from './login-page'\n\nclass Props {\n loginCallback!: () => void\n}\n\n/*\n * Note:\n * If the authentication fails, we'd like to call loginCallback to notify the app component\n * that the user is logged out (because they might have been logged in before coming here).\n * Unfortunately that would cause the app component to re-mount this component and hence \n * cause an infinite loop so we can't do it.\n * \n * Fortunately thing the user can do from here is to navigate manually which this which will\n * reload the app component anyway, so it doesn't matter that we're putting it into an\n * inconsistent state.\n*/\n\nexport default function ReviewerLogin({ loginCallback }: Props) {\n const locaton = useLocation()\n const token = new URLSearchParams(locaton.search).get(\"token\") ?? \"\"\n const [failed, setFailed] = useState(false)\n\n useEffect(\n () => {\n const authenticate = async () => {\n const response = await cupidFetch('/api/session', 'POST', { token })\n if (!response) return\n const subject = new Subject(response)\n if (!subject.isAuthenticated()) {\n setFailed(true)\n // see note above\n } else {\n loginCallback()\n }\n }\n authenticate()\n },\n [loginCallback, token]\n )\n\n return (\n
\n {failed ? \"Invalid authentication token\" : \"Logging in, please wait...\"}\n
\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport cupidFetch from \"../../modules/cupid-fetch\";\nimport { Link } from 'react-router-dom';\nimport Subject from '../../modules/data-objects/subject';\nimport Logo from '../../IHEEM-logo.png'\nimport useReactSimpleMatchMedia from 'react-simple-matchmedia'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faUnlockAlt } from '@fortawesome/free-solid-svg-icons'\nimport { NavEntry } from './app-config';\n\nclass Props {\n loginCallback!: () => void;\n subject!: Subject;\n getNavEntries!: (subject:Subject) => NavEntry[]\n}\n\nenum MenuState {\n Small, // window width < 640px, nav is hidden, menu button shown\n SmallWithMenu, // window width < 640px, nav is shown, menu button shown\n NotSmall // window width >= 640px nav is shown, menu button shown hidden\n}\n/*\n * We say \"NotSmall\" as opposed to \"Large\" to be consistent with Foundation terminology (it means medium or large)\n * initial state is Small or NotSmall\n * transitions between the states are:\n * Small => SmallWithMenu - user clicks menu button\n * SmallWithMenu => Small - user clicks menu button or selects an item from the nav\n * Small or SmallWithMenu => NotSmall - user makes window bigger\n * NotSmall => Small - user makes window smaller\n *\n * Note the 640 is the default value in Foundation. If that gets changed, you'll need to change it here as well\n */\n\nfunction Nav({ loginCallback, subject, getNavEntries }: Props) {\n const smallScreen: boolean = !useReactSimpleMatchMedia('(min-width: 640px)');\n const [menuState, setMenuState] = useState(smallScreen ? MenuState.Small : MenuState.NotSmall)\n\n // detect window changing size\n useEffect(\n () => {\n if (smallScreen && menuState === MenuState.NotSmall) {\n setMenuState(MenuState.Small)\n }\n if (!smallScreen && menuState !== MenuState.NotSmall) {\n setMenuState(MenuState.NotSmall)\n }\n },\n [smallScreen, menuState]\n )\n\n const logout = async () => {\n const response = await cupidFetch(\"/api/session\", \"DELETE\", null);\n if (response) {\n loginCallback()\n }\n }\n\n const onMenuButtonClick = () => {\n setMenuState(menuState === MenuState.Small ? MenuState.SmallWithMenu : MenuState.Small)\n }\n\n const hideMenu = () => {\n if (menuState === MenuState.SmallWithMenu) {\n setMenuState(MenuState.Small)\n }\n }\n\n return (\n <>\n {menuState !== MenuState.NotSmall &&\n
\n \n
Menu
\n
\n }\n
\n
\n
\n
\n
\n \"IHEEM\n
\n
\n
\n {menuState !== MenuState.Small &&\n
\n
    \n {getNavEntries(subject).map((o, i) =>\n
  • \n {o.text}\n
  • \n )}\n
  • \n Logout\n
  • \n
\n
\n }\n
\n
\n \n );\n}\n\nexport default Nav;\n","import React from 'react'\nimport Nav from './nav'\nimport Subject from '../../modules/data-objects/subject'\nimport { NavEntry } from './app-config'\n\nclass Props {\n loginCallback!: () => void\n subject!: Subject\n renderLayoutRoutes!: (subject: Subject) => JSX.Element\n getNavEntries!: (subject: Subject) => NavEntry[]\n}\n\nfunction Layout({ subject, loginCallback, renderLayoutRoutes, getNavEntries }: Props) {\n return (\n
\n
\n )\n}\n\nexport default Layout\n","import ActivityType from \"./activity-type\";\nimport { getGlobal } from \"../globals\";\n\nexport default class SysInfo {\n app!: string\n buildDate!: string\n activityTypes!: ActivityType[]\n clientAppConfig!: ClientAppConfig\n}\n\nclass ClientAppConfig {\n autoSaveInterval!: number\n activityList!: ActivityList\n}\n\nclass ActivityList {\n startYear!: number\n endYear!: number\n}\n\nclass SysInfoGlobals {\n // we're defaulting sysInfo to null to make sure you don't access it until it's been set properly\n sysInfo: SysInfo = null!\n}\n\nconst globalName = \"sysInfo\";\n\nexport function getSysInfoGlobals(): SysInfoGlobals {\n return getGlobal(SysInfoGlobals, globalName);\n}\n\nexport function getSysInfo(): SysInfo {\n return getSysInfoGlobals().sysInfo\n}\n","import React from 'react';\nimport { getAlertGlobals } from '../../modules/show-alert';\n\nclass State {\n message: string | null = null;\n isConfirm: boolean | null = null;\n}\n\ntype Resolver = (value: any) => void;\n\n// because alerts are async, there can be any number of them present at any one time.\n// we queue them up and only show the second one once the first has been dismissed.\nclass QueueEntry {\n message: string;\n resolver: Resolver;\n isConfirm: boolean;\n promise: Promise;\n constructor(message: string, isConfirm: boolean, promise: Promise, resolver: Resolver) {\n this.message = message;\n this.isConfirm = isConfirm;\n this.promise = promise;\n this.resolver = resolver;\n }\n}\n\nclass AlertBox extends React.Component<{}, State> {\n state: State = new State();\n queue: QueueEntry[] = [];\n\n constructor(props: {}) {\n super(props);\n const globals = getAlertGlobals();\n globals.showAlert = this.showAlert.bind(this);\n globals.showConfirm = this.showConfirm.bind(this);\n }\n\n // We don't want to queue up loads of identical messages unless they are confirms,\n // so when we come to add a new one, if it's not a confirm and there's already an identical\n // one in the queue (which includes being already displayed), we just return the same promise\n // so it will resolve when the user accepts the first one.\n addAlertToQueue(message: string, isConfirm: boolean): Promise {\n if (!isConfirm) {\n const queueEntry = this.queue.find(o => o.message === message && !o.isConfirm);\n if (queueEntry != null) {\n return queueEntry.promise!;\n }\n }\n let resolver: Resolver;\n const promise = new Promise((r: Resolver) => {\n resolver = r;\n });\n // we're guaranteed resolver is set now, even though the compiler doesn't know that\n this.queue.push(new QueueEntry(message, isConfirm, promise, resolver!));\n if (this.queue.length === 1) {\n this.setState({ message, isConfirm });\n }\n return promise;\n }\n\n showAlert(message: string): Promise {\n return this.addAlertToQueue(message, false);\n }\n\n showConfirm(message: string): Promise {\n return this.addAlertToQueue(message, true);\n }\n\n buttonClicked(result: boolean) {\n if (this.queue.length < 1) {\n throw new Error(\"alert button clicked when no alert shown\");\n }\n this.queue.shift()!.resolver(result);\n // show the next message or, if the queue is empty, nothing\n if (this.queue.length) {\n const { message, isConfirm } = this.queue[0];\n this.setState({ message, isConfirm });\n } else {\n this.setState({ message: null, isConfirm: null });\n }\n }\n\n render() {\n return (\n this.state.message != null\n ?\n
\n
\n

{this.state.message}

\n
\n \n {this.state.isConfirm &&\n \n }\n
\n
\n
\n :\n null\n );\n }\n}\n\nexport default AlertBox\n","import { getGlobal, deleteGlobal } from './globals';\n\nexport type ShowAlertType = (message: string) => Promise;\nexport type ShowConfirmType = (message: string) => Promise;\n\nconst globalName = \"currentDate\";\n\nclass CurrentDateGlobals {\n getCurrentDate: () => Date = () => new Date();\n}\n\nexport function getCurrentDateGlobals(): CurrentDateGlobals {\n return getGlobal(CurrentDateGlobals, globalName);\n}\n\nexport function resetCurrentDateGlobals(): void {\n deleteGlobal(globalName);\n}\n\nexport default function getCurrentDate(): Date {\n return getCurrentDateGlobals().getCurrentDate();\n}\n","import { format, parse } from \"date-fns\"\nimport getCurrentDate from \"./current-date\";\n\n/*\n * Dates without a time are a completely different concept\n * from dates as a point in time - consider 2 people born on opposite sides of the world\n * at the same moment. although their birth as a point in time is the same, and their\n * age in seconds will always be the same, their birthday as shown in their passport\n * will be different, no matter where in the world they go.\n * \n * Some dates in the system such as activity date are the same concept as birthday,\n * if we try to manipulate such dates as timestamps, we wil get messed around by automatic\n * timezone conversions when passing the date between client, server, and database, so\n * the safest thing to do is just store them as strings\n */\n\nexport const displayDateFormat = \"d MMM yyyy\";\nconst internalDateFormat = \"yyyy-MM-dd\"\n\nexport const formatDateWithoutTimeForDisplay = (date: string | null): string =>\n date ? format(parseDateWithoutTime(date)!, displayDateFormat) : \"\"\n\nexport const getCurrentDateWithoutTime = (): string => formatDateWithoutTime(getCurrentDate());\n\nexport const startOfYear = (year: number) => `${year}-01-01`\nexport const endOfYear = (year: number) => `${year}-12-31`\n\n/*\n * these 2 functions are not exported - you should not be trying to convert between\n * date without time and js Date because of the problems noted above\n */\nconst formatDateWithoutTime = (date: Date): string => format((date), internalDateFormat);\nconst parseDateWithoutTime = (s: string): Date => parse(s, internalDateFormat, new Date())\n","import _ from \"lodash\";\nimport { getCurrentDateWithoutTime } from \"../date-without-time\";\n\nexport default class Activity {\n activityId: string | null = null;\n userId: string | null = null;\n activityTypeId: string | null = null;\n title: string = \"\";\n activityDate: string | null = null;\n isEventSession: boolean = false;\n eventSessionCode: string = \"\";\n competencyRef: string = \"\";\n isCompleted: boolean = false;\n points: number | null = null;\n hours: number | null = null;\n expectedLearning: string = \"\";\n actualLearning: string = \"\";\n impact: string = \"\";\n comments: string = \"\";\n hasNotes: boolean = false;\n}\n\n/**\n * santitizes an Activity parsed from JSON. the parameter isn't really an activity object,\n * it's a JSON object with the same properties as an activity object!\n * @param activity \n */\nexport function activityFromJson(activity: Activity) : Activity {\n return {\n ...new Activity(),\n ...activity,\n title: activity.title ?? \"\",\n eventSessionCode: activity.eventSessionCode ?? \"\",\n competencyRef: activity.competencyRef ?? \"\",\n points: activity.points ?? null,\n hours: activity.hours ?? null,\n expectedLearning: activity.expectedLearning ?? \"\",\n actualLearning: activity.actualLearning ?? \"\",\n impact: activity.impact ?? \"\",\n comments: activity.comments ?? \"\",\n activityDate: activity.activityDate ?? null,\n }\n}\n\nexport function newActivity(activityId: string | null): Activity {\n return {\n ...new Activity(),\n activityId,\n activityDate: getCurrentDateWithoutTime()\n }\n}\n\nexport function activityIsEmpty(activity: Activity) {\n return !(activity.title || activity.eventSessionCode);\n}\n\nexport function activityEquals(activity1: Activity, activity2: Activity, ignoreIsCompleted: boolean): boolean {\n return !_.isEqual(\n activity1,\n { ...activity2, isCompleted: ignoreIsCompleted ? activity1.isCompleted : activity2.isCompleted }\n );\n}\n","import React from 'react';\nimport cupidFetch from \"../../modules/cupid-fetch\";\nimport Activity, { activityFromJson, newActivity } from '../../modules/data-objects/activity';\nimport { showAlert } from '../../modules/show-alert';\nimport VerifyEventSessionResult from '../../modules/data-objects/verify-event-session-result';\n\nclass Props {\n eventSessionMode!: boolean;\n eventSessionSelected!: (eventSession: Activity | null) => void;\n initialEventSessionCode!: string;\n dirtyCallback!: (dirty: boolean) => void;\n activityId!: string | null;\n}\n\n// there are basically 5 cases for the state:\n// 1. old and new values both blank => button disabled\n// 2. old value blank => verify\n// 3. new value blank => clear\n// 4. old and new are the same => clear\n// 5. old and new different => verify\n\nclass State {\n eventSessionCode: string = \"\";\n constructor(initialEventSessionCode: string) {\n this.eventSessionCode = initialEventSessionCode;\n }\n}\n\nclass EventSessionCode extends React.Component {\n state: State = new State(this.props.initialEventSessionCode);\n\n async componentDidUpdate(prevProps: Props) {\n if (prevProps.initialEventSessionCode !== this.props.initialEventSessionCode) {\n this.setState({ eventSessionCode: this.props.initialEventSessionCode });\n }\n }\n\n eventSessionCodeOnChange = (event: React.ChangeEvent) => {\n const value = event.target.value;\n this.setState({ eventSessionCode: value });\n this.props.dirtyCallback(value !== this.props.initialEventSessionCode);\n }\n\n async verifyEventSession(eventSessionCode: string) {\n const url = `/api/activities/verifyeventsession?eventsessioncode=${encodeURIComponent(eventSessionCode)}`\n return await cupidFetch(url, \"GET\");\n }\n\n async eventSessionModeVerify(clear: boolean) {\n if (this.props.initialEventSessionCode) {\n // case 3, 4, 5\n const previousEventSession = await this.verifyEventSession(this.props.initialEventSessionCode);\n if (!previousEventSession) return;\n if (previousEventSession.existingActivity) {\n await showAlert(`Previous Session code \"${this.props.initialEventSessionCode}\" still in use`);\n this.setState({ eventSessionCode: this.props.initialEventSessionCode });\n this.props.dirtyCallback(false);\n return;\n }\n }\n if (!clear) {\n // case 2, 5\n const newEventSession = await this.verifyEventSession(this.state.eventSessionCode);\n if (!newEventSession) return;\n if (newEventSession.eventSession && newEventSession.eventSession.activityId !== this.props.activityId) {\n await showAlert(`Session code \"${this.state.eventSessionCode}\" already in use`);\n return;\n }\n }\n if (clear) {\n this.props.eventSessionSelected(null);\n this.setState({ eventSessionCode: \"\" })\n } else {\n this.props.eventSessionSelected({ ...newActivity(null), eventSessionCode: this.state.eventSessionCode });\n }\n }\n\n async normalModeVerify(clear: boolean) {\n if (clear) {\n // case 3, 4\n this.props.eventSessionSelected(null);\n this.setState({ eventSessionCode: \"\" })\n } else {\n // case 2, 5\n const response = await this.verifyEventSession(this.state.eventSessionCode);\n if (!response) return;\n if (!response.eventSession) {\n await showAlert(`Session code \"${this.state.eventSessionCode}\" could not be found`);\n return;\n }\n // if you delete the session code then add it back again immediately before an auto-save, you\n // will get back existingActivity as current activity but that's not an error\n if (response.existingActivity && response.existingActivity.activityId !== this.props.activityId) {\n await showAlert(`Session code \"${this.state.eventSessionCode}\" already referenced by another activity`);\n return;\n }\n const eventSession = activityFromJson(response.eventSession);\n this.props.eventSessionSelected(eventSession);\n this.setState({ eventSessionCode: eventSession.eventSessionCode });\n }\n }\n\n onVerifyClick = async (event: React.MouseEvent) => {\n const target = event.target as HTMLButtonElement;\n const clear: boolean = target.textContent === \"Clear\";\n if (this.props.eventSessionMode) {\n this.eventSessionModeVerify(clear);\n } else {\n this.normalModeVerify(clear);\n }\n };\n\n render() {\n const { buttonLabel, buttonDisabled } = getButtonState(this.state.eventSessionCode, this.props.initialEventSessionCode);\n return (\n
\n
\n {/* the label is styled wrongly but needed for testing - really we should just fix the styling */}\n \n Session code\n \n
\n \n
\n
\n
\n )\n }\n}\n\n// this function exported for unit testing\nexport function getButtonState(eventSessionCode: string, verifiedCode: string) {\n const buttonLabel = (!verifiedCode || (eventSessionCode && eventSessionCode !== verifiedCode))\n ? \"Verify\"\n : \"Clear\";\n const buttonDisabled = !verifiedCode && !eventSessionCode;\n return { buttonLabel, buttonDisabled };\n}\n\nexport default EventSessionCode;\n","import React from 'react';\nimport cupidFetch from \"../../modules/cupid-fetch\";\nimport Attachment from '../../modules/data-objects/attachment';\nimport { showConfirm } from '../../modules/show-alert';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faCloudDownloadAlt, faTrash } from '@fortawesome/free-solid-svg-icons'\n\nclass Props {\n title!: string;\n activityId!: string | null;\n anyAttachmentsCallback?: (anyAttachments: boolean) => void;\n enableDelete?: boolean\n}\n\nclass State {\n attachments: Attachment[] = [];\n}\n\nclass AttachmentList extends React.Component {\n mounted: boolean = false;\n state: State = new State();\n\n anyAttachmentsCallback(anyAttachments: boolean) {\n if (this.props.anyAttachmentsCallback) {\n this.props.anyAttachmentsCallback(anyAttachments)\n }\n }\n\n async refreshAttachmentList() {\n if (!this.props.activityId) {\n this.setState({ attachments: [] });\n this.anyAttachmentsCallback(false);\n return\n }\n if (!this.mounted) return;\n const attachments = await cupidFetch(\n `/api/activities/${this.props.activityId}/attachments`);\n if (!this.mounted) return;\n if (attachments) {\n this.setState({ attachments });\n this.anyAttachmentsCallback(!!attachments.length)\n }\n }\n\n async componentDidMount() {\n this.mounted = true;\n await this.refreshAttachmentList();\n }\n\n componentWillUnmount() {\n this.mounted = false;\n }\n\n onDeleteClick = async (event: React.MouseEvent, attachmentId: string) => {\n event.preventDefault();\n const attachment = this.state.attachments.find(o => o.attachmentId === attachmentId)!\n if (!await showConfirm(`Delete this attachment \"${attachment.fileName}\"?`)) {\n return;\n }\n const result = await cupidFetch(\n `/api/activities/${attachment.activityId}/attachments/${attachment.attachmentId}`,\n \"DELETE\")\n if (!result) return\n await this.refreshAttachmentList()\n }\n\n render() {\n if (!this.state.attachments.length) {\n return null;\n }\n return (\n <>\n
{this.props.title}
\n \n \n );\n }\n}\n\nexport function reformatFileName(s?: string | null): string {\n if (!s) return \"\"\n const i = s.lastIndexOf(\".\")\n return i === -1\n ? s\n : `${s.substr(0, i)} (${s.substr(i + 1).toLowerCase()})`\n}\n\nexport default AttachmentList;\n","import React from 'react';\nimport AttachmentList from './attachment-list';\nimport Activity from '../../modules/data-objects/activity';\nimport cupidFetch from '../../modules/cupid-fetch';\nimport VerifyEventSessionResult from '../../modules/data-objects/verify-event-session-result';\n\nclass Props {\n activity!: Activity;\n attachmentListNonce!: number;\n anyAttachmentsCallback?: (anyAttachments: boolean) => void;\n enableDelete?: boolean;\n}\n\nclass State {\n eventSessionActivityId: string | null = null;\n}\n\nclass AttachmentLists extends React.Component {\n state: State = new State()\n mounted: boolean = false\n\n componentDidMount() {\n this.mounted = true;\n this.getEventSessionActivityId()\n }\n\n componentWillUnmount() {\n this.mounted = false;\n }\n\n async getEventSessionActivityId() {\n if (!this.props.activity.isEventSession && this.props.activity.eventSessionCode) {\n const url = `/api/activities/verifyeventsession?eventsessioncode=${encodeURIComponent(this.props.activity.eventSessionCode)}`;\n const response = await cupidFetch(url);\n if (!this.mounted) return;\n this.setState({ eventSessionActivityId: response?.eventSession?.activityId! })\n } else {\n this.setState({ eventSessionActivityId: null })\n }\n }\n\n async componentDidUpdate(prevProps: Props) {\n if (prevProps.activity.eventSessionCode !== this.props.activity.eventSessionCode) {\n this.getEventSessionActivityId()\n }\n }\n\n render() {\n return (\n <>\n \n

 

\n \n \n );\n }\n}\n\nexport default AttachmentLists;\n","import React, { ChangeEventHandler, FormEventHandler } from 'react';\nimport { showAlert } from '../../modules/show-alert';\nimport parseProblem from '../../modules/rfc7807-problem';\n\nclass Props {\n activityId!: string | null;\n uploadInProgressCallback!: (inProgress: boolean) => void;\n saveActivityCallback!: () => Promise;\n}\n\n/*\n * if an upload is in progress, request is not null. note that\n * progress goes to 100% before the upload is complete so we can't\n * use that to determine whether it's still uploading, completed or\n * failed; we can only use that to show the progress bar.\n */\nclass State {\n file: string = \"\";\n lastSuccessfulFile: string = \"\";\n progress: number = 0;\n request: XMLHttpRequest | null = null;\n}\n\nclass FileUpload extends React.Component {\n state: State = new State();\n formRef: React.RefObject = React.createRef();\n\n fileUploadSuccess = async () => {\n this.setState(state => ({ file: \"\", lastSuccessfulFile: extractFilename(state.file) }));\n }\n\n fileUploadError = () => {\n showAlert(\"Could not contact server - check network status and try again\");\n }\n\n fileUploadComplete = (): void => {\n if (this.state.request!.status === 200) {\n this.fileUploadSuccess();\n } else {\n this.fileUploadFailed();\n }\n this.setState({ request: null })\n this.props.uploadInProgressCallback(false);\n }\n\n fileUploadFailed = () => {\n const request = this.state.request!;\n const problem = parseProblem(request.getResponseHeader(\"content-type\"), request.responseText);\n const errorMessage = problem ?? \"Could not contact server - check network status and try again\";\n showAlert(errorMessage);\n }\n\n fileSelectorChange: ChangeEventHandler = async e => {\n const file = e.target.value;\n this.setState({ file, lastSuccessfulFile: \"\" });\n if (file) {\n if (!this.props.activityId) {\n const saveOk = await this.props.saveActivityCallback();\n if (!saveOk) return;\n }\n const formElement = this.formRef.current!;\n formElement.dispatchEvent(new Event('submit', { cancelable: true }));\n }\n }\n\n fileUploadProgress = (e: ProgressEvent) => {\n this.setState({ progress: e.loaded / e.total });\n }\n\n performUpload = (formData: FormData) => {\n this.props.uploadInProgressCallback(true);\n this.setState({ request: new XMLHttpRequest() }, () => {\n const request = this.state.request!;\n request.onload = () => this.fileUploadComplete();\n request.onerror = () => { this.fileUploadError() };\n request.upload.onprogress = e => { this.fileUploadProgress(e) }\n request.open(\"POST\", `/api/activities/${this.props.activityId}/attachments`);\n request.send(formData);\n });\n }\n\n cancelUpload = () => {\n this.state.request!.abort();\n this.setState({ progress: 0, request: null });\n this.props.uploadInProgressCallback(false);\n }\n\n onSubmit: FormEventHandler = e => {\n e.preventDefault();\n if (this.state.request) {\n this.cancelUpload();\n } else {\n const formData = new FormData(e.target as HTMLFormElement);\n this.performUpload(formData)\n }\n }\n\n render() {\n const showProgress = this.state.progress > 0 && this.state.progress < 1;\n const uploading = !!this.state.request;\n const caption = uploading ? \"Cancel\" : \"Upload\";\n return (\n
\n
\n \n \n {showProgress && }\n \n {!this.state.request && extractFilename(this.state.file)}\n \n \n {!!this.state.lastSuccessfulFile &&\n
\n

file {this.state.lastSuccessfulFile} uploaded OK

\n \n
\n }\n \n
\n );\n }\n}\n\n// this code copied from https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type%3Dfile)\nfunction extractFilename(path: string): string {\n if (path.substr(0, 12) === \"C:\\\\fakepath\\\\\")\n return path.substr(12); // modern browser\n var x;\n x = path.lastIndexOf('/');\n if (x >= 0) // Unix-based path\n return path.substr(x + 1);\n x = path.lastIndexOf('\\\\');\n if (x >= 0) // Windows-based path\n return path.substr(x + 1);\n return path; // just the file name\n}\n\nexport default FileUpload;\n","import React from 'react'\n\nclass Props {\n value!: string\n onChange!: (value: string) => void\n form?: string\n id?: string\n placeholder?: string\n}\n\nexport function DateInput({ value, onChange, form, placeholder, id }: Props) {\n\n function dateOnChange(event: React.ChangeEvent) {\n if (event.target.validity.valid) {\n onChange(event.target.value!);\n }\n }\n\n return \n}\n","import React from 'react';\nimport Activity from '../../modules/data-objects/activity';\nimport { nanToNull, text_expected_learning, text_actual_learning, text_impact, text_comments } from '../../modules/utils';\nimport { getSysInfo } from '../../modules/data-objects/sys-info';\nimport { DateInput } from '../utils/date-input';\nimport TextareaAutosize from 'react-textarea-autosize';\n\nclass Props {\n activity!: Activity\n updateFieldCallback!: (updates: Partial) => void;\n}\n\nclass MainInputFields extends React.Component {\n\n fieldOnChange = (event: React.ChangeEvent | React.ChangeEvent | React.ChangeEvent) => {\n // we can't declare updates as Partial because we're assigning properties dynamically\n const updates: any = {}\n updates[event.target.id] = event.target.value\n this.props.updateFieldCallback(updates);\n }\n\n pointsOnChange = (event: React.ChangeEvent) => {\n if (event.target.validity.valid) {\n this.props.updateFieldCallback({ points: nanToNull(parseInt(event.target.value)) });\n }\n }\n\n hoursOnChange = (event: React.ChangeEvent) => {\n if (event.target.validity.valid) {\n this.props.updateFieldCallback({ hours: nanToNull(parseFloat(event.target.value)) });\n }\n }\n\n activityDateOnChange = (value: string) => this.props.updateFieldCallback({ activityDate: value })\n\n render() {\n const activityTypes = [{ activityTypeId: \"\", title: \"\" }, ...getSysInfo().activityTypes]\n return (\n <>\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n {!this.props.activity.isEventSession &&\n <>\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n \n }\n \n );\n }\n}\n\nexport default MainInputFields;\n","import React from 'react'\nimport Subject from '../../modules/data-objects/subject'\n\nclass Props {\n subject!: Subject\n}\n\nexport function LoggedInAs({ subject }: Props) {\n const authenticated = subject.authenticated!\n\n const getDescription = () => {\n switch (true) {\n case subject.isCpdUser(): return (\n Membership No. {authenticated.membershipNo || \"n/a\"}\n )\n case subject.isSysadmin(): return (\n (Sysadmin)\n )\n case subject.isReviewer(): return (\n Email {authenticated.emailAddress}\n )\n }\n }\n\n return (\n

\n You are logged in as {authenticated.displayName}\n | \n {getDescription()}\n

\n )\n}\n","import React from 'react';\nimport Activity, { newActivity, activityEquals, activityIsEmpty, activityFromJson } from '../../modules/data-objects/activity';\nimport { withRouter, RouteComponentProps } from 'react-router-dom';\nimport Subject from '../../modules/data-objects/subject';\nimport { getSysInfo } from '../../modules/data-objects/sys-info';\nimport { showConfirm } from '../../modules/show-alert';\nimport cupidFetch from '../../modules/cupid-fetch';\nimport EventSessionCode from './event-session-code';\nimport AttachmentLists from './attachment-lists';\nimport FileUpload from './file-upload';\nimport MainInputFields from './main-input-fields';\nimport { LoggedInAs } from '../utils/logged-in-as';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faTrash } from '@fortawesome/free-solid-svg-icons'\nimport { faCheckCircle } from '@fortawesome/free-regular-svg-icons'\nimport { iheemWebSiteUrl } from '../app/app';\n\nclass Props {\n activityId?: string | null;\n returnUrl?: string | null;\n subject!: Subject;\n}\n\nclass State {\n activity: Activity;\n lastSavedActivity: Activity;\n waitingForServer: boolean = false;\n uploadInProgress: boolean = false;\n lastAutoSaveFailed: boolean = false;\n anyAttachments: boolean | null = null;\n attachmentListNonce: number = 0;\n eventSessionCodeDirty: boolean = false;\n isCompletedOverride: boolean = false;\n constructor(activityId: string | null, subject: Subject) {\n this.activity = newActivity(activityId);\n this.activity.isEventSession = subject.isSysadmin()\n this.lastSavedActivity = { ...this.activity };\n }\n}\n\nclass _EditCpd extends React.Component {\n state: State = new State(this.props.activityId ?? null, this.props.subject);\n autoSaveTimer: NodeJS.Timeout | null = null;\n firstSavePromise: Promise | null = null;\n mounted: boolean = false\n\n isNew = () => !(this.state.activity.activityId);\n\n isDirty = (ignoreIsCompleted: boolean) =>\n this.isNew() || activityEquals(this.state.activity, this.state.lastSavedActivity, ignoreIsCompleted);\n\n setAutoSaveTimer() {\n const interval = getSysInfo().clientAppConfig.autoSaveInterval;\n if (!interval) {\n throw new Error(`autoSaveInterval is ${interval}`);\n }\n this.autoSaveTimer = setInterval(() => this.saveActivity(true), interval);\n }\n\n goBack() {\n this.props.history.push(this.props.returnUrl ?? \"/\");\n }\n\n async componentDidMount() {\n this.mounted = true\n if (this.isNew()) {\n this.setAutoSaveTimer();\n } else {\n await this.fetchActivity();\n }\n }\n\n componentWillUnmount() {\n this.mounted = false\n if (this.autoSaveTimer) {\n clearInterval(this.autoSaveTimer);\n this.autoSaveTimer = null;\n }\n }\n\n componentDidUpdate(prevProps: Props, prevState: State) {\n /* \n * if the user is editing an activity which was completed, we'll set it back to draft when it becomes\n * dirty (and back to completed if it becomes clean again). However, once the user has clicked one\n * of the radio buttons (i.e. isCompletedOverride = true) we stop doing that.\n * Event sessions don't have the same rule because we can't set them back to draft in case\n * they are referenced.\n */\n if (!this.state.activity.isEventSession && !this.state.isCompletedOverride) {\n const isCompleted: boolean = !this.isDirty(true) && this.state.lastSavedActivity.isCompleted;\n if (isCompleted !== this.state.activity.isCompleted) {\n this.updateFields({ isCompleted });\n }\n }\n }\n\n updateFields = (updates: Partial) => {\n this.setState(state => ({ activity: { ...state.activity, ...updates } }));\n }\n\n isCompletedChange = (event: React.ChangeEvent) => {\n const isCompleted = event.target.value === \"true\";\n this.updateFields({ isCompleted });\n this.setState({ isCompletedOverride: true });\n }\n\n eventSessionSelected = (selectedEventSession: Activity | null) => {\n /*\n * There's 3 scenarios for this callback:\n * 1. user has just verified an event session code => copy values from the event session\n * 2. user has just cleared the event session code => blank out the values\n * 3. we're editing an event session => just use the event session code directly\n */\n const eventSession = selectedEventSession ?? newActivity(null);\n const extraUpdates: Partial = this.state.activity.isEventSession\n ? {}\n : {\n activityDate: eventSession.activityDate,\n title: eventSession.title,\n activityTypeId: eventSession.activityTypeId,\n points: eventSession.points,\n hours: eventSession.hours,\n }\n this.updateFields({ eventSessionCode: eventSession.eventSessionCode, ...extraUpdates })\n this.setState({ eventSessionCodeDirty: false })\n }\n\n eventSessionCodeDirtyCallback = (dirty: boolean): void => this.setState({ eventSessionCodeDirty: dirty });\n\n // doSave returns true if the save worked or if there was no need to save\n fileUploadSaveActivityCallback = async (): Promise => this.saveActivity(false);\n\n uploadInProgressCallback = async (inProgress: boolean) => {\n this.setState({ uploadInProgress: inProgress });\n if (!inProgress) {\n // an upload completed or failed, so let's refresh the attachments\n this.setState(state => ({ attachmentListNonce: state.attachmentListNonce + 1 }));\n }\n }\n\n anyAttachmentsCallback = (anyAttachments: boolean) => this.setState({ anyAttachments });\n\n onCloseClick = async () => {\n if (this.state.eventSessionCodeDirty) {\n if (!await (showConfirm(\"You haven't verified changes to the session code. do you want to save without it?\"))) {\n return;\n }\n }\n if (this.isDirty(false) && this.state.lastAutoSaveFailed) {\n if (await (showConfirm(\"Activity has not been saved, do you want to exit without saving?\"))) {\n this.goBack();\n return;\n }\n }\n this.setState({ waitingForServer: true });\n const saveOk = await this.saveActivity(false);\n this.setState({ waitingForServer: false });\n if (saveOk) {\n this.goBack();\n }\n }\n\n onDeleteClick = async () => {\n // note: anyAttachments will be null if the attachments list hasn't loaded yet. we play safe\n // and still show the message in this case.\n if (!activityIsEmpty(this.state.activity) || this.state.anyAttachments !== false) {\n if (!await showConfirm(\"Are you sure you want to delete this CPD record?\")) {\n return;\n }\n }\n this.setState({ waitingForServer: true });\n let navigatedAway: boolean = false;\n try {\n // Step 1: if we're in the middle of creating the activity on the server, we need to\n // wait until we know whether that worked or not\n let activityId: string | null;\n if (this.firstSavePromise) {\n const result = await this.firstSavePromise;\n if (!result) {\n return;\n }\n activityId = result.activityId;\n } else {\n activityId = this.state.activity.activityId;\n }\n // Step 2: delete the activity if it exists\n if (activityId !== null) {\n const result = await cupidFetch(`/api/activities/${activityId}`, \"DELETE\");\n if (result == null) {\n // delete failed so don't leave the screen\n return;\n }\n }\n navigatedAway = true;\n this.goBack();\n } finally {\n if (!navigatedAway) {\n this.setState({ waitingForServer: false });\n }\n }\n }\n\n async fetchActivity() {\n this.setState({ waitingForServer: true });\n const result = await cupidFetch(`/api/activities/${this.state.activity.activityId}`);\n if (result) {\n if (!this.mounted) return\n const activity = activityFromJson(result);\n this.setState(state => ({\n activity,\n lastSavedActivity: { ...activity },\n waitingForServer: false,\n }));\n this.setAutoSaveTimer();\n }\n }\n\n // returns true if the save worked or if there was no need to save\n async saveActivity(isAutoSave: boolean): Promise {\n if (!this.isDirty(isAutoSave)) {\n return true;\n }\n const method = this.isNew() ? \"POST\" : \"PATCH\";\n const urlSuffix = this.isNew() ? \"\" : `/${this.state.activity.activityId}`;\n // normal activities are always auto-saved as draft, but completed event sessions are \n // auto-saved as completed because they might be referenced by activities\n const activityToSave = {\n ...this.state.activity,\n isCompleted: isAutoSave && !this.state.activity.isEventSession ? false : this.state.activity.isCompleted\n }\n const promise = cupidFetch(`/api/activities${urlSuffix}`, method, activityToSave);\n if (this.isNew()) {\n this.firstSavePromise = promise;\n }\n const result = await promise;\n this.firstSavePromise = null;\n if (result) {\n const activity = activityFromJson(result);\n this.setState({ lastSavedActivity: activity });\n if (this.isNew()) {\n this.setState(state => ({\n activity: { ...state.activity, activityId: activity.activityId, userId: activity.userId }\n }\n ));\n const returnUrl = encodeURIComponent(this.props.returnUrl ?? \"/\")\n this.props.history.push(`/activities/${activity.activityId}/edit?returnurl=${returnUrl}`)\n }\n }\n if (isAutoSave) {\n this.setState({ lastAutoSaveFailed: !result });\n }\n return !!result;\n }\n\n render() {\n const fieldsDisabled = this.state.waitingForServer;\n const buttonsDisabled = this.state.uploadInProgress || this.state.waitingForServer;\n const competencyRefLink = `${iheemWebSiteUrl}/registration/#competances_downloads`\n const sessionCodeLink = `${iheemWebSiteUrl}/learning-hub/library/iheem-mycpd-system-session-codes/`\n\n return (\n
\n
\n
\n

Edit CPD

\n \n
\n
\n
\n
\n

Helpful Hints:

\n

Session code – for preloaded IHEEM CPD activity you attended, enter the event session code and click Verify. This will prepopulate all standard fields and backup resources.\n For a list of all session codes see\n \n {sessionCodeLink}.\n

\n

For non session code CPD, enter the relevant data from Title onwards.

\n

Competency reference – for you to reference the Engineering Council competency if required.\n For details of the relevant competency codes based on your registration type see\n \n {competencyRefLink}.\n If you want to put more than one reference against a single activity, enter using a comma and space between each one (Eg. 1A, 2C).\n

\n

You must complete the following four questions to be able to complete your piece of CPD. You can also upload multiple file attachments.

\n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n \n \n \n \n \n
\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n );\n }\n}\n\nconst EditCpd = withRouter(_EditCpd);\nexport default EditCpd;\n","import { RouteComponentProps, withRouter } from 'react-router-dom';\nimport React from 'react';\nimport cupidFetch from '../modules/cupid-fetch';\nimport VerifyEventSessionResult from '../modules/data-objects/verify-event-session-result';\nimport Activity, { newActivity, activityFromJson } from '../modules/data-objects/activity';\n\nclass Props {\n eventSessionCode?: string | null;\n}\n\nclass State {\n message: string = \"Loading...\";\n}\n\nclass _AddOrEditCpd extends React.Component {\n state: State = new State();\n\n async componentDidMount() {\n if (!this.props.eventSessionCode) {\n this.setState({ message: \"Error: No event session code specified\" });\n return;\n }\n const url = `/api/activities/verifyeventsession?eventsessioncode=${encodeURIComponent(this.props.eventSessionCode)}`\n const verifyEventSessionResult = await cupidFetch(url, \"GET\");\n if (!verifyEventSessionResult) return;\n if (verifyEventSessionResult.existingActivity) {\n this.props.history.push(`/activities/${verifyEventSessionResult.existingActivity.activityId}/edit`);\n } else if (!verifyEventSessionResult.eventSession) {\n this.setState({ message: `Error: Event Session code ${this.props.eventSessionCode} not found` });\n } else {\n const activity = newActivity(null);\n const eventSession = activityFromJson(verifyEventSessionResult.eventSession)\n activity.activityDate = eventSession.activityDate;\n activity.eventSessionCode = eventSession.eventSessionCode;\n activity.title = eventSession.title;\n const savedActivity = await cupidFetch(`/api/activities`, \"POST\", activity);\n if (!savedActivity) return null;\n this.props.history.push(`/activities/${savedActivity.activityId}/edit`);\n }\n }\n\n render() {\n return <>\n
{this.state.message}
\n \n ;\n }\n}\n\nconst AddOrEditCpd = withRouter(_AddOrEditCpd);\nexport default AddOrEditCpd;\n","export default class ActivityNote {\n activityNoteId: string | null = null\n activityId: string | null = null\n reviewerName: string | null = null\n reviewerEmail: string | null = null\n noteDate: Date | null = null\n noteText: string = \"\"\n}\n\nexport function activityNoteFromJson(activityNote: ActivityNote) : ActivityNote {\n return {\n ...new ActivityNote(),\n ...activityNote,\n noteDate: new Date(activityNote.noteDate!.valueOf()),\n }\n}\n","import React, { useState, useEffect } from 'react'\nimport ActivityNote, { activityNoteFromJson } from '../../modules/data-objects/activity-note'\nimport Subject from '../../modules/data-objects/subject'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport { showConfirm } from '../../modules/show-alert'\nimport { formatDateTimeForDisplay } from '../../modules/data-objects/date-utils'\nimport TextareaAutosize from 'react-textarea-autosize';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPen, faTrash } from '@fortawesome/free-solid-svg-icons'\nimport { faCheckCircle } from '@fortawesome/free-regular-svg-icons'\n\nclass Props {\n activityId!: string\n activityNote!: ActivityNote | null\n subject!: Subject\n dirtyNoteCallback!: (dirty: boolean) => void\n}\n\nexport default function NoteDetails({ activityId, activityNote, subject, dirtyNoteCallback }: Props) {\n const [editMode, setEditMode] = useState(!activityNote)\n const [noteDate, setNoteDate] = useState(activityNote?.noteDate)\n const [noteText, setNoteText] = useState(activityNote?.noteText ?? \"\")\n const [waitingForServer, setWaitingForServer] = useState(false)\n const [activityNoteId, setActivityNoteId] = useState(activityNote?.activityNoteId)\n const dirty = (editMode && !!(activityNoteId || noteText))\n const reviewerEmail = activityNote?.reviewerEmail ?? subject.authenticated!.emailAddress\n const reviewerName = activityNote?.reviewerName ?? subject.authenticated!.displayName\n const editButtonVisible = !editMode && subject.isReviewer()\n const acceptButtonVisible = editMode && subject.isReviewer()\n const deleteButtonVisible = subject.isReviewer()\n const acceptButtonEnabled = acceptButtonVisible && noteText\n\n useEffect(\n () => {\n dirtyNoteCallback(dirty)\n },\n [dirty, dirtyNoteCallback]\n )\n\n const noteTextChange = (event: React.ChangeEvent) => setNoteText(event.target.value)\n\n const getUrl = () => {\n const suffix = activityNoteId ? `/${activityNoteId}` : \"\"\n return `/api/activities/${activityId}/notes${suffix}`\n }\n\n const onAcceptClick = async () => {\n const method = activityNoteId ? \"PATCH\" : \"POST\"\n const payload: ActivityNote = { ...new ActivityNote(), noteText }\n setWaitingForServer(true)\n const result = await cupidFetch(getUrl(), method, payload)\n setWaitingForServer(false)\n if (!result) return\n const newActivityNote = activityNoteFromJson(result)\n setActivityNoteId(newActivityNote.activityNoteId)\n setNoteDate(newActivityNote.noteDate)\n setEditMode(false)\n }\n\n const onDeleteClick = async () => {\n if (activityNoteId || noteText) {\n if (!await showConfirm(\"Delete this note?\")) return\n }\n if (activityNoteId) {\n setWaitingForServer(true)\n const result = await cupidFetch(getUrl(), \"DELETE\")\n setWaitingForServer(false)\n if (!result) return\n }\n setNoteText(\"\")\n setNoteDate(null)\n setActivityNoteId(null)\n setEditMode(true)\n }\n\n const onEditClick = () => {\n setEditMode(true)\n }\n\n return (\n
\n
\n
Note from: {reviewerName} ({reviewerEmail}) {formatDateTimeForDisplay(noteDate)}
\n {editMode\n ? \n :

{noteText}

\n }\n
\n
\n {editButtonVisible && }\n {acceptButtonVisible && }\n {deleteButtonVisible && }\n
\n
\n )\n}\n","import { displayDateFormat } from \"../date-without-time\";\nimport { format } from \"date-fns\"\n\nexport function formatDateTimeForDisplay(date?: Date | null) {\n if (!date) return \"\";\n return format(date!, displayDateFormat + \" HH:mm\");\n}\n","import React, { useState, useEffect } from 'react'\nimport Activity from '../../modules/data-objects/activity'\nimport ActivityNote, { activityNoteFromJson } from '../../modules/data-objects/activity-note'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport NoteDetails from './note-details'\nimport Subject from '../../modules/data-objects/subject'\n\nclass Props {\n activity!: Activity\n subject!: Subject\n dirtyNoteCallback!: (dirty: boolean) => void\n}\n\nexport default function ActivityNoteList({ activity, subject, dirtyNoteCallback }: Props) {\n // if there are no notes and the user is a reviewer, we still want to render the activity note control,\n // which we do by passing in null for the note object\n const [activityNotes, setActivityNotes] = useState<(ActivityNote | null)[]>([])\n const url = `/api/activities/${activity.activityId}/notes`\n\n useEffect(\n () => {\n let isMounted = true;\n (async () => {\n const result = await cupidFetch(url)\n if (!isMounted) return\n if (!result) return\n setActivityNotes(\n !result.length && subject.isReviewer()\n ? [null]\n : result.map(o => activityNoteFromJson(o))\n )\n })()\n return () => { isMounted = false }\n },\n [url, subject]\n )\n\n return (\n <>\n {activityNotes.map(o =>\n \n )}\n \n )\n}\n","import React from 'react';\nimport { useHistory } from 'react-router-dom'\nimport Activity, { activityFromJson } from '../../modules/data-objects/activity';\nimport { text_expected_learning, text_actual_learning, text_impact, text_comments, encodeCurrentUrl } from '../../modules/utils';\nimport AttachmentLists from '../edit-cpd/attachment-lists';\nimport { formatDateWithoutTimeForDisplay } from '../../modules/date-without-time';\nimport { getSysInfo } from '../../modules/data-objects/sys-info';\nimport ActivityNoteList from './activity-note-list';\nimport Subject from '../../modules/data-objects/subject';\nimport { showConfirm } from '../../modules/show-alert';\nimport cupidFetch from '../../modules/cupid-fetch';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPen } from '@fortawesome/free-solid-svg-icons'\nimport { faCheckCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons'\n\nclass Props {\n activity!: Activity\n subject!: Subject\n dirtyNoteCallback!: (dirty: boolean) => void\n reloadActivityList!: () => void\n}\n\nexport default function ActivityDetails({ activity, dirtyNoteCallback, subject, reloadActivityList }: Props) {\n const history = useHistory()\n\n const activityType = activity.activityTypeId\n ? getSysInfo().activityTypes.find(o => o.activityTypeId === activity.activityTypeId)?.title\n : \"n/a\"\n\n const editButtonClick = () => {\n const returnUrl = encodeCurrentUrl(history)\n history.push(`/activities/${activity.activityId}/edit?returnurl=${returnUrl}`)\n }\n\n const deleteButtonClick = async () => {\n if (!await showConfirm(`Delete this activity \"${activity.title}\"`)) return\n const result = await cupidFetch(`/api/activities/${activity.activityId}`, \"DELETE\")\n if (!result) return\n reloadActivityList()\n }\n\n const completeButtonClick = async () => {\n if (!await showConfirm(`Complete this activity \"${activity.title}\"`)) return\n const result = await cupidFetch(`/api/activities/${activity.activityId}`)\n if (!result) return\n const fetchedActivity = activityFromJson(result)\n fetchedActivity.isCompleted = true\n const result2 = await cupidFetch(`/api/activities/${fetchedActivity.activityId}`, \"PATCH\", fetchedActivity)\n if (!result2) return\n reloadActivityList()\n }\n\n return (\n
\n
\n
\n

{activity.title}

\n {!subject.isReviewer() &&\n
\n \n {!activity.isCompleted && <>\n \n \n }\n
\n }\n
\n

Activity type: {activityType}

\n

Date: {formatDateWithoutTimeForDisplay(activity.activityDate)}

\n {activity.eventSessionCode &&

Event session code: {activity.eventSessionCode}

}\n {activity.points &&

Points: {activity.points}

}\n {activity.hours &&

Hours: {activity.hours}

}\n {activity.competencyRef &&

Competency ref: {activity.competencyRef}

}\n
\n \n
\n
\n {activity.expectedLearning && <>\n
{text_expected_learning}
\n

{activity.expectedLearning}

\n }\n {activity.actualLearning && <>\n
{text_actual_learning}
\n

{activity.actualLearning}

\n }\n {activity.impact && <>\n
{text_impact}
\n

{activity.impact}

\n }\n {activity.comments && <>\n
{text_comments}
\n

{activity.comments}

\n }\n \n
\n
\n
\n );\n}\n","import React from 'react'\nimport SlideDown from 'react-slidedown'\nimport { getGlobal } from '../../modules/globals';\nimport 'react-slidedown/lib/slidedown.css'\n\nconst globalName = \"slideDown\";\n\nclass Props {\n children!: false | JSX.Element\n}\n\nexport function getSlideDownGlobals(): SlideDownGlobals {\n return getGlobal(SlideDownGlobals, globalName);\n}\n\nexport class SlideDownGlobals {\n enableTransitions: boolean = true;\n}\n\nexport default function CupidSlideDown({ children }: Props) {\n return (\n <>\n {getSlideDownGlobals().enableTransitions\n ? {children}\n : children\n }\n \n )\n}\n","import React, { useState } from 'react'\nimport Activity from '../../modules/data-objects/activity'\nimport ActivityDetails from './activity-details'\nimport { formatDateWithoutTimeForDisplay } from '../../modules/date-without-time'\nimport { showAlert } from '../../modules/show-alert'\nimport Subject from '../../modules/data-objects/subject'\nimport { AccordionItem, AccordionTitle, AccordionContent } from 'react-foundation'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faFileAlt } from '@fortawesome/free-regular-svg-icons'\nimport CupidSlideDown from '../utils/cupid-slidedown'\n\nclass Props {\n activity!: Activity\n reloadActivityList!: () => void\n subject!: Subject\n}\n\nexport default function ActivityListRow({ activity, reloadActivityList, subject }: Props) {\n const [expanded, setExpanded] = useState(false)\n const [allowContract, setallowContract] = useState(true)\n\n const expandButtonClick = () => {\n if (expanded && !allowContract) {\n showAlert(\"You are currently editing a note. Please either save or delete the note to continue.\")\n return;\n }\n setExpanded(expanded => !expanded)\n }\n\n return (\n \n \n \n {formatDateWithoutTimeForDisplay(activity.activityDate)}\n | \n {activity.title}\n {activity.hasNotes &&\n <>\n \n \n \n }\n \n \n \n {expanded &&\n \n setallowContract(!dirty)}\n reloadActivityList={reloadActivityList} />\n \n }\n \n \n )\n}\n","import React from 'react'\nimport Activity from '../../modules/data-objects/activity'\nimport ActivityListRow from './activity-list-row'\nimport Subject from '../../modules/data-objects/subject'\nimport { Accordion, AccordionItem, AccordionTitle } from 'react-foundation'\n\nclass Props {\n activities: Activity[] | null = null\n reloadActivityList!: () => void\n subject!: Subject\n}\n\nconst ActivityListView = ({ activities, reloadActivityList, subject }: Props) =>\n
\n \n {!activities ?\n \n Loading...\n \n : activities.length === 0 ?\n \n No activities\n \n :\n activities.map(o =>\n \n )\n }\n \n
\n\nexport default ActivityListView\n","import { endOfYear, startOfYear } from \"../date-without-time\"\nimport getCurrentDate from \"../current-date\"\n\nexport default class ReviewGrant {\n reviewGrantId: string | null = null\n accessToken: string | null = null\n userId: string | null = null\n expiryDate!: string\n activityStartDate!: string\n activityEndDate!: string\n reviewerName: string = \"\"\n reviewerEmail: string = \"\"\n}\n\nexport function reviewGrantFromJson(reviewGrant: ReviewGrant) : ReviewGrant {\n return {\n ...new ReviewGrant(),\n ...reviewGrant,\n }\n}\n\nexport function newReviewGrant(reviewGrantId: string | null): ReviewGrant {\n const year = getCurrentDate().getFullYear()\n return {\n ...new ReviewGrant(),\n reviewGrantId,\n expiryDate: endOfYear(year),\n activityStartDate: startOfYear(year),\n activityEndDate: endOfYear(year),\n }\n}\n","import React from 'react'\nimport { differenceInDays } from \"date-fns\"\nimport getCurrentDate from '../../modules/current-date'\nimport GaugeChart from 'react-gauge-chart'\n\nclass Props {\n target!: number | null\n actual!: number\n title!: string\n year!: number\n}\n\nexport const gaugeWouldRender = (target: number | null, actual: number) => !!(target || actual)\n\nexport default function ProgressGauge({ target, actual, title, year }: Props) {\n const yearStart = new Date(year, 0, 1);\n const yearEnd = new Date(year, 11, 31);\n const totalDaysInYear = differenceInDays(yearEnd, yearStart) + 1\n const daysSoFar = differenceInDays(getCurrentDate(), yearStart) + 1\n\n return (<>\n {gaugeWouldRender(target, actual) &&\n
\n
{title} target: {target ?? \"n/a\"}; actual: {actual}
\n target ? (actual / target * 100).toFixed(0) + \"%\" : \"no target\"}\n />\n
Jan {year}
\n
Dec {year}
\n
\n
}\n )\n}\n","import React, { useState, useEffect } from 'react'\nimport Subject from '../../modules/data-objects/subject'\nimport TargetProgress from '../../modules/data-objects/target-progress'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport getCurrentDate from '../../modules/current-date'\nimport ProgressGauge, { gaugeWouldRender } from './progress-gauge'\n\nclass Props {\n subject!: Subject\n year?: number\n userId?: string\n}\n\nexport default function ProgressWidget({ subject, year, userId }: Props) {\n const [targetPoints, setTargetPoints] = useState(null)\n const [targetHours, setTargetHours] = useState(null)\n const [actualPoints, setActualPoints] = useState(0)\n const [actualHours, setActualHours] = useState(0)\n const [loaded, setLoaded] = useState(false)\n const selectedYear = year ?? getCurrentDate().getFullYear()\n\n useEffect(\n () => {\n let isMounted = true;\n (async () => {\n const userSuffix = userId ? `?userid=${userId}` : \"\"\n const result = await cupidFetch(`/api/activities/targetprogress/${selectedYear}${userSuffix}`)\n if (result && isMounted) {\n setTargetPoints(result.targetPoints)\n setTargetHours(result.targetHours)\n setActualPoints(result.actualPoints)\n setActualHours(result.actualHours)\n setLoaded(true)\n }\n })()\n return () => { isMounted = false }\n },\n [selectedYear, userId]\n )\n\n return (\n <>\n {!subject.isSysadmin() && (gaugeWouldRender(targetPoints, actualPoints) || gaugeWouldRender(targetHours, actualHours)) &&\n
\n \n \n \n
\n }\n \n )\n}\n","import React, { useState, useEffect } from 'react'\nimport Subject from '../../modules/data-objects/subject'\nimport Activity, { activityFromJson } from '../../modules/data-objects/activity'\nimport ActivityListView from './activity-list-view'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport { reviewGrantFromJson } from '../../modules/data-objects/review-grant'\nimport ProgressWidget from '../target-progress/progress-widget'\nimport { startOfYear, endOfYear } from '../../modules/date-without-time'\nimport { LoggedInAs } from '../utils/logged-in-as'\n\nclass Props {\n subject!: Subject\n}\n\nfunction getFullYear(startDate: string, endDate: string): number | null {\n const year = parseInt(startDate.split(\"-\")[0])\n return startDate === startOfYear(year) && endDate === endOfYear(year)\n ? year\n : null\n}\n\nexport default function ReviewerActivityList({ subject }: Props) {\n const [activities, setActivities] = useState([])\n const authenticated = subject.authenticated!\n const reviewer = authenticated.reviewer!\n const reviewGrant = reviewGrantFromJson(reviewer.reviewGrant)\n const url = `/api/activities?userid=${reviewGrant.userId}&startdate=${reviewGrant.activityStartDate}&enddate=${reviewGrant.activityEndDate}`\n const year = getFullYear(reviewGrant.activityStartDate, reviewGrant.activityEndDate)\n\n useEffect(\n () => {\n let isMounted = true;\n (async () => {\n const result = await cupidFetch(url)\n if (!isMounted) return\n if (!result) return\n setActivities(result.map(o => activityFromJson(o)))\n })()\n return () => { isMounted = false }\n },\n [subject, url]\n )\n\n return (\n <>\n
\n
\n
\n

\n Review CPD for \n {reviewer.revieweeName}\n
\n (Membership No. \n {reviewer.revieweeMewmbershipNo}\n )\n

\n \n
\n
\n {year &&\n
\n
\n \n
\n
\n }\n
\n { }} activities={activities} subject={subject} />\n \n )\n}\n","import React from 'react'\nimport cupidFetch from \"../../modules/cupid-fetch\"\nimport Activity, { activityFromJson } from '../../modules/data-objects/activity'\nimport ActivityListView from './activity-list-view'\nimport Subject from '../../modules/data-objects/subject'\n\nclass State {\n activities: Activity[] | null = null\n}\n\nclass Props {\n queryString!: string\n reloadActivityList!: () => void\n subject!: Subject\n}\n\nclass ActivityList extends React.Component {\n state: State = new State()\n mounted: boolean = false\n\n async componentDidMount() {\n this.mounted = true\n this.loadActivityList()\n }\n\n loadActivityList = async () => {\n const url = `/api/activities${this.props.queryString}`\n const activities = await cupidFetch(url)\n if (!this.mounted) return\n if (activities) {\n this.setState({ activities: activities!.map(o => activityFromJson(o)) })\n }\n }\n\n reloadActivityList = async () => {\n await this.loadActivityList()\n this.props.reloadActivityList()\n }\n\n componentWillUnmount() {\n this.mounted = false\n }\n\n render() {\n return (\n \n )\n }\n}\n\nexport default ActivityList\n","import React, { useState } from 'react';\nimport { useHistory, useLocation } from 'react-router-dom';\nimport _ from \"lodash\";\nimport { getSysInfo } from '../../modules/data-objects/sys-info';\nimport getCurrentDate from '../../modules/current-date';\nimport ActivityList from './activity-list';\nimport { startOfYear, endOfYear } from '../../modules/date-without-time';\nimport { encodeCurrentUrl } from '../../modules/utils';\nimport ProgressWidget from '../target-progress/progress-widget';\nimport Subject from '../../modules/data-objects/subject';\nimport { LoggedInAs } from '../utils/logged-in-as';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPlusCircle } from '@fortawesome/free-solid-svg-icons'\n\nclass YearSelectorEntry {\n title!: string\n queryString!: string\n year!: number | null\n}\n\nclass Props {\n subject!: Subject\n}\n\nconst queryStringFromDateRange = (startDate: string, endDate: string) =>\n `?startdate=${startDate}&enddate=${endDate}`\n\nconst queryStringFromYearRange = (startYear: number, endYear: number) =>\n queryStringFromDateRange(startOfYear(startYear), endOfYear(endYear))\n\nconst queryStringFromYear = (year: number) => queryStringFromYearRange(year, year)\n\nconst getCurrentRange = (startDate: string | null, endDate: string | null): string =>\n (startDate || endDate)\n ? queryStringFromDateRange(startDate!, endDate!)\n : queryStringFromYear(getCurrentDate().getFullYear())\n\nfunction getYearSelectorValues(selectedRange: string): YearSelectorEntry[] {\n const activityListConfig = getSysInfo().clientAppConfig.activityList\n const yearRange: YearSelectorEntry[] = _.range(activityListConfig.startYear, activityListConfig.endYear + 1)\n .map(year => ({\n title: year.toString(),\n queryString: queryStringFromYear(year),\n year\n }))\n yearRange.push({\n title: \"Other\",\n queryString: queryStringFromYearRange(activityListConfig.endYear + 1, activityListConfig.startYear - 1),\n year: null\n })\n if (!yearRange.some(o => o.queryString === selectedRange)) {\n yearRange.push({\n title: \"Custom\",\n queryString: \"Custom\",\n year: null\n })\n }\n return yearRange\n}\n\nfunction ActivityListPage({ subject }: Props) {\n const history = useHistory()\n const location = useLocation()\n const [nonce, setNonce] = useState(0)\n\n function yearOnChange(event: React.ChangeEvent) {\n const value = event.target.value;\n history.push(`/activities${value}`);\n }\n\n const newButtonClick = () => {\n const returnUrl = encodeCurrentUrl(history);\n history.push(`/activities/new?returnurl=${returnUrl}`);\n }\n\n const reloadActivityList = () => {\n setNonce(oldValue => oldValue + 1)\n }\n\n const searchParams = new URLSearchParams(location.search)\n const startDateString = searchParams.get(\"startdate\")\n const endDateString = searchParams.get(\"enddate\")\n const selectedRange = getCurrentRange(startDateString, endDateString)\n const yearSelectorValues = getYearSelectorValues(selectedRange)\n const selectedEntry = yearSelectorValues.find(o => o.queryString === selectedRange) ?? yearSelectorValues[yearSelectorValues.length - 1]\n\n return (\n <>\n
\n
\n
\n

My CPD

\n \n
\n
\n
\n
\n

Below is your full MyIHEEM CPD record (italics represents CPD in draft status). Click on an activity to expand the details.

\n

To add a new piece of CPD activity, click on the New CPD button.

\n

The gauges below show your actual points and hours to date against targeted for the selected calendar year.

\n {selectedEntry.year &&\n \n }\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n\n \n \n )\n}\n\nexport default ActivityListPage;\n","import React from 'react'\nimport ReviewGrant from '../../modules/data-objects/review-grant'\nimport { formatDateWithoutTimeForDisplay } from '../../modules/date-without-time'\nimport { showConfirm, showAlert } from '../../modules/show-alert'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPen, faTrash, faEnvelope } from '@fortawesome/free-solid-svg-icons'\n\nclass Props {\n reviewGrant!: ReviewGrant\n startEditing!: () => void\n deleteGrant!: (reviewGrantId: string) => void\n waitingForServer!: boolean\n}\n\nexport default function ViewGrant({ reviewGrant, startEditing, deleteGrant, waitingForServer }: Props) {\n\n const sendNotification = async () => {\n const msg = `Send an email notification to ${reviewGrant.reviewerEmail}?`\n if (!await showConfirm(msg)) return\n const response = await cupidFetch(`/api/reviewgrants/${reviewGrant.reviewGrantId}/sendnotification`, \"POST\")\n if (!response) return\n await showAlert(\"Email notification sent successfully.\\nIf the reviewer has not received the email within half an hour, make sure they check their \\\"junk\\\" or \\\"spam\\\" folder.\")\n }\n\n return (\n <>\n
\n

{reviewGrant.reviewerName}

\n
\n
\n \n \n \n
\n
\n
\n
\n
\n

Email: {reviewGrant.reviewerEmail}

\n

Expires: {formatDateWithoutTimeForDisplay(reviewGrant.expiryDate)}

\n

Activity from: {formatDateWithoutTimeForDisplay(reviewGrant.activityStartDate)}

\n

Activity to: {formatDateWithoutTimeForDisplay(reviewGrant.activityEndDate)}

\n
\n
\n \n )\n}\n","import React, { useState, FormEvent } from 'react'\nimport ReviewGrant from '../../modules/data-objects/review-grant'\nimport { DateInput } from '../utils/date-input'\n\nclass Props {\n reviewGrant!: ReviewGrant\n cancelEdit!: () => void\n saveEdit!: (updates: Partial) => void\n waitingForServer!: boolean\n}\n\n/*\n * for the date fields, we don't update the state in the change handler unless they are valid, but\n * for the email this makes no sense because you can't start typing an email address as it is \n * initially invalid, so we update the state even if the address is invalid. However, the form\n * won't submit if it's invalid (and the browser will automatically show the validation error).\n */\nexport default function EditGrant({ reviewGrant, cancelEdit, saveEdit, waitingForServer }: Props) {\n const [reviewerEmail, setReviewerEmail] = useState(reviewGrant.reviewerEmail)\n const [reviewerName, setReviewerName] = useState(reviewGrant.reviewerName)\n const [expiryDate, setexpiryDate] = useState(reviewGrant.expiryDate)\n const [activityStartDate, setActivityStartDate] = useState(reviewGrant.activityStartDate)\n const [activityEndDate, setActivityEndDate] = useState(reviewGrant.activityEndDate)\n const key = reviewGrant.reviewGrantId\n\n async function onSubmit(event: FormEvent) {\n event.preventDefault()\n const form = event.target as HTMLFormElement\n if (!form.checkValidity()) return // this line only needed for unit testing due to https://github.com/jsdom/jsdom/issues/2898\n const updated = {\n reviewGrantId: reviewGrant.reviewGrantId,\n reviewerEmail, reviewerName, expiryDate, activityStartDate, activityEndDate\n }\n saveEdit(updated)\n }\n\n return (\n
\n
\n
\n
\n
\n \n
\n
\n setReviewerName(e.target.value)}\n />\n
\n
\n \n
\n
\n setReviewerEmail(e.target.value)}\n />\n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n )\n}\n","import React, { useState } from 'react'\nimport ReviewGrant from '../../modules/data-objects/review-grant'\nimport ViewGrant from './view-grant'\nimport EditGrant from './edit-grant'\nimport { AccordionItem, AccordionTitle, AccordionContent } from 'react-foundation'\nimport { formatDateWithoutTimeForDisplay } from '../../modules/date-without-time'\nimport { showAlert } from '../../modules/show-alert'\nimport CupidSlideDown from '../utils/cupid-slidedown'\n\nclass Props {\n reviewGrant!: ReviewGrant\n saveEdit!: (updates: Partial) => void\n deleteGrant!: (reviewGrantId: string | null) => void\n waitingForServer!: boolean\n initiallyExpanded!: boolean\n}\n\nexport default function ReviewGrantRow({ reviewGrant, saveEdit, deleteGrant, waitingForServer, initiallyExpanded }: Props) {\n const [editing, setEditing] = useState(!reviewGrant.reviewGrantId)\n const [expanded, setExpanded] = useState(initiallyExpanded || !reviewGrant.reviewGrantId)\n\n const expandButtonClick = () => {\n if (expanded && editing) {\n showAlert(\"You are currently editing - please save or cancel\")\n return;\n }\n setExpanded(expanded => !expanded)\n }\n\n const startEditing = () => setEditing(true)\n\n const cancelEditing = () => {\n setEditing(false)\n if (!reviewGrant.reviewGrantId) {\n deleteGrant(reviewGrant.reviewGrantId)\n }\n }\n\n const onSaveEdit = (updates: Partial) => {\n saveEdit(updates)\n setEditing(false)\n }\n\n return (\n \n {\n reviewGrant.reviewGrantId\n ? <>\n {reviewGrant.reviewerName}\n | \n {formatDateWithoutTimeForDisplay(reviewGrant.expiryDate)}\n \n : \"New reviewer\"\n }\n \n \n {expanded &&\n \n
\n {editing\n ? \n : \n }\n
\n
\n }\n
\n
\n )\n}\n","import React from 'react'\nimport { RouteComponentProps, withRouter } from 'react-router-dom'\nimport ReviewGrant, { reviewGrantFromJson, newReviewGrant } from '../../modules/data-objects/review-grant'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport ReviewGrantRow from './review-grant-row'\nimport { showConfirm, showAlert } from '../../modules/show-alert'\nimport { LoggedInAs } from '../utils/logged-in-as'\nimport Subject from '../../modules/data-objects/subject'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPlusCircle } from '@fortawesome/free-solid-svg-icons'\nimport { Accordion, AccordionItem, AccordionTitle } from 'react-foundation'\n\n/* We need to talk about newSaveId...\n *\n * When the user adds a new one, it goes into the list with an ID of null. when it's saved for the first time\n * the id changes. but of course, the id is the key for the so we need to be a bit clever,\n * and this means remembering the ID of the most recent newly saved one. It's used in 2 places:\n * \n * 1. When retrieving a list from the server into state, if the current state contains an unsaved one we need to add that\n * to the top of the list unless we've just done a new save (in which case the newly saved one will be already included)\n * \n * 2. When rendering the for the newly saved one for the first time, we want it to be expanded so\n * that the user can click the email button if they like.\n * \n * note that even with this jiggery-pokery, a newly saved row is removed from state and added back in with a different\n * id, so it slides up and back down in a different place which isn't ideal. maybe a better solution would be to\n * use our own ID for the key which stays constant and map this into the server id separately.\n */\n\nclass State {\n reviewGrants: ReviewGrant[] | null = null\n waitingForServer: boolean = false\n newSaveId: string | null = null;\n}\n\nclass Props {\n subject!: Subject;\n}\n\nclass _ReviewGrantPage extends React.Component {\n state: State = new State()\n mounted: boolean = false\n\n async componentDidMount() {\n this.mounted = true\n this.loadReviewGrants(null)\n }\n\n async loadReviewGrants(newSaveId: string | null) {\n const reviewGrants = await cupidFetch(\"/api/reviewgrants\")\n if (!this.mounted) return\n if (!reviewGrants) return\n this.setState(state => ({\n newSaveId,\n reviewGrants: [\n ...(state.reviewGrants ?? []).filter(o => !o.reviewGrantId && !newSaveId),\n ...reviewGrants!.map(o => reviewGrantFromJson(o))\n ]\n }))\n }\n\n componentWillUnmount() { this.mounted = false }\n\n saveEdit = async (updates: Partial) => {\n this.setState({ waitingForServer: true })\n const reviewGrantId = updates.reviewGrantId;\n this.setState(state => ({\n reviewGrants:\n state.reviewGrants!.map(o =>\n o.reviewGrantId === reviewGrantId\n ? { ...o, ...updates }\n : o)\n }), async () => {\n const isNew = !updates.reviewGrantId\n const method = isNew ? \"POST\" : \"PATCH\"\n const urlSuffix = isNew ? \"\" : `/${reviewGrantId}`\n const toSave = this.state.reviewGrants?.find(o => o.reviewGrantId === reviewGrantId)\n const saveResult = await cupidFetch(`/api/reviewgrants${urlSuffix}`, method, toSave)\n if (!saveResult) return\n const newSaveId = isNew ? saveResult.reviewGrantId : null\n await this.loadReviewGrants(newSaveId)\n if (!this.mounted) return\n this.setState({ waitingForServer: false })\n if (isNew) {\n await showAlert(\"Reviewer access has been granted. Click \\\"send email\\\" to send them an email with a link to review your CPD record.\")\n }\n })\n }\n\n deleteGrant = async (reviewGrantId: string | null) => {\n if (reviewGrantId) {\n if (!await showConfirm(\"Delete this grant?\")) return\n this.setState(state => ({\n reviewGrants:\n state.reviewGrants!.filter(o => o.reviewGrantId !== reviewGrantId)\n }))\n await cupidFetch(`/api/reviewgrants/${reviewGrantId}`, \"DELETE\")\n this.loadReviewGrants(null)\n } else {\n this.setState(state => ({ reviewGrants: state.reviewGrants!.filter(o => o.reviewGrantId) }))\n }\n }\n\n createGrant = () => {\n this.setState(state => ({ reviewGrants: [newReviewGrant(null), ...state.reviewGrants!] }))\n }\n\n renderTableBody(): JSX.Element[] | JSX.Element {\n if (!this.state.reviewGrants) return (\n \n Loading...\n \n ); else if (this.state.reviewGrants.length === 0) return (\n \n No review access granted\n \n ); else return (\n this.state.reviewGrants.map(reviewGrant =>\n \n )\n )\n }\n\n render() {\n // you can only add a new one if the list has loaded and there aren't any new ones already\n const enableAdd = !this.state.waitingForServer && this.state.reviewGrants && !(this.state.reviewGrants.find(o => !o.reviewGrantId))\n return (\n <>\n
\n
\n
\n

Grant reviewer access

\n \n
\n
\n
\n
\n

\n You can grant a number of reviewers access to your CPD to view and make notes.\n Reviewers cannot see each others' notes.\n For each reviewer, enter the the date their access expires, and the date range of activity they can view.\n When you are ready for them to have access, click \"Send email\" which will send them an invitation email with a link to review the CPD.\n

\n
\n
\n
\n
\n
\n \n {this.renderTableBody()}\n \n
\n
\n
\n \n
\n
\n \n )\n }\n}\n\nconst ReviewGrantPage = withRouter(_ReviewGrantPage)\nexport default ReviewGrantPage\n","import React, { useState, useEffect, FormEvent } from 'react'\nimport cupidFetch from '../modules/cupid-fetch'\nimport getCurrentDate from '../modules/current-date'\nimport { nanToNull } from '../modules/utils'\nimport Target from '../modules/data-objects/target'\nimport { useHistory } from 'react-router-dom'\nimport Subject from '../modules/data-objects/subject'\nimport { LoggedInAs } from './utils/logged-in-as'\n\nclass Props {\n subject!: Subject\n}\n\nexport default function Targets({ subject }: Props) {\n const history = useHistory()\n const [points, setPoints] = useState(null)\n const [hours, setHours] = useState(null)\n const [loaded, setLoaded] = useState(false)\n const year = getCurrentDate().getFullYear()\n\n useEffect(\n () => {\n let isMounted = true\n ; (async () => {\n const result = await cupidFetch(`/api/targets/${year}`)\n if (result && isMounted) {\n setPoints(result.points)\n setHours(result.hours)\n setLoaded(true)\n }\n })()\n return () => { isMounted = false }\n },\n [year]\n )\n\n const pointsOnChange = (event: React.ChangeEvent) => {\n if (event.target.validity.valid) {\n setPoints(nanToNull(parseInt(event.target.value)))\n }\n }\n\n const hoursOnChange = (event: React.ChangeEvent) => {\n if (event.target.validity.valid) {\n setHours(nanToNull(parseFloat(event.target.value)))\n }\n }\n\n const onCloseClick = async (event: FormEvent) => {\n event.preventDefault()\n const target: Target = { hours, points }\n const result = await cupidFetch(`/api/targets/${year}`, \"PATCH\", target)\n if (result) {\n history.push(\"/\")\n }\n }\n\n return (\n
\n
\n
\n

Set targets

\n \n
\n
\n
\n
\n

If you have annual targets for either or both points and hours enter them here. These are used to show your actual against target position to date as you move throughout the year.

\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n )\n}\n","import React, { useState, useEffect, FormEvent } from 'react'\nimport User from '../modules/data-objects/user'\nimport cupidFetch from '../modules/cupid-fetch'\nimport { useHistory } from 'react-router-dom'\nimport { LoggedInAs } from './utils/logged-in-as'\nimport Subject from '../modules/data-objects/subject'\n\nconst webFormName = \"CPD App\"\n\nclass Props {\n subject!: Subject;\n}\n\nexport default function UserDetails({ subject }: Props) {\n const history = useHistory()\n const [user, setUser] = useState(null)\n const [waitingForServer, setWaitingForServer] = useState(false)\n\n const fieldOnChange = (event: React.ChangeEvent) => {\n const updatedUser = { ...user } as any\n updatedUser[event.target.id] = event.target.value\n setUser(updatedUser)\n }\n\n useEffect(\n () => {\n let isMounted = true\n ; (async () => {\n setWaitingForServer(true)\n const result = await cupidFetch(`/api/user`)\n if (result && isMounted) {\n setWaitingForServer(false)\n setUser(result)\n }\n })()\n return () => { isMounted = false }\n },\n []\n )\n\n const onCloseClick = async (event: FormEvent) => {\n event.preventDefault()\n setWaitingForServer(true)\n const payload = { ...user!, webFormName }\n const result = await cupidFetch(`/api/user`, \"PATCH\", payload)\n setWaitingForServer(false)\n if (!result) return\n history.push(\"/\")\n }\n\n const renderRow = (attrName: string, label: string, maxLength: number = 100) => {\n const untypedUser = (user as any)\n const webFormAttrName = \"webForm\" + attrName[0].toUpperCase() + attrName.slice(1)\n return (<>\n
\n \n
\n
\n \n
\n
\n \n
\n )\n }\n\n return (\n
\n
\n
\n

Update user details

\n \n
\n
\n
\n
\n

This area is for you to tell us of any changes to your user details, please amend where required in\n the New value box (only fill in what's changed). Note these are not applied instantly; \n we will review them and update your membership record accordingly.

\n
\n
\n
\n
\n
\n
\n
\n
\n
\n {renderRow(\"salutation\", \"Title\", 20)}\n {renderRow(\"firstName\", \"First name\")}\n {renderRow(\"lastName\", \"Last name\")}\n {renderRow(\"addressLine1\", \"Street address 1\")}\n {renderRow(\"addressLine2\", \"Street address 2\")}\n {renderRow(\"addressLine3\", \"Street address 3\")}\n {renderRow(\"city\", \"City\")}\n {renderRow(\"county\", \"County/State\")}\n {renderRow(\"postCode\", \"Postal code\")}\n {renderRow(\"country\", \"Country\")}\n {renderRow(\"jobTitle\", \"Job title\")}\n {renderRow(\"organisation\", \"Organisation\")}\n {renderRow(\"businessPhone\", \"Business phone\")}\n {renderRow(\"mobilePhone\", \"Mobile phone\")}\n {renderRow(\"email\", \"Email\")}\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n )\n}\n","import React from 'react'\nimport cupidFetch from \"../../modules/cupid-fetch\"\nimport Activity, { activityFromJson } from '../../modules/data-objects/activity'\nimport ActivityListView from './activity-list-view'\nimport Subject from '../../modules/data-objects/subject'\n\nclass State {\n activities: Activity[] | null = null\n}\n\nclass Props {\n reloadActivityList!: () => void\n subject!: Subject\n}\n\nclass DraftActivityList extends React.Component {\n state: State = new State()\n mounted: boolean = false\n\n async componentDidMount() {\n this.mounted = true\n this.loadActivityList()\n }\n\n loadActivityList = async () => {\n this.mounted = true\n const url = \"/api/activities?alluncompleted=true\"\n const activities = await cupidFetch(url)\n if (!this.mounted) return\n if (activities) {\n this.setState({ activities: activities!.map(o => activityFromJson(o)) })\n }\n }\n\n reloadActivityList = async () => {\n await this.loadActivityList()\n this.props.reloadActivityList()\n }\n\n componentWillUnmount() {\n this.mounted = false\n }\n\n render() {\n return (\n this.state.activities && (!!this.state.activities.length) &&\n \n )\n }\n}\n\nexport default DraftActivityList\n","import React, { useState } from 'react';\nimport Subject from '../../modules/data-objects/subject';\nimport { RouteComponentProps, withRouter } from 'react-router-dom';\nimport DraftActivityList from '../activity-list/draft-activity-list';\nimport ProgressWidget from '../target-progress/progress-widget';\nimport { LoggedInAs } from '../utils/logged-in-as';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faPlusCircle } from '@fortawesome/free-solid-svg-icons'\n\nclass Props {\n subject!: Subject;\n}\n\nfunction _Home({ subject, history }: Props & RouteComponentProps) {\n const [nonce, setNonce] = useState(0)\n\n const onNewCpdClick = () => {\n history.push(\"/activities/new\");\n }\n\n const reloadActivityList = () => {\n setNonce(oldValue => oldValue + 1)\n }\n\n return (\n <>\n
\n
\n
\n

MyIHEEM CPD

\n \n
\n
\n
\n
\n

Welcome to MyIHEEM CPD, your system for recording your lifelong learning outcomes.

\n

MyIHEEM CPD has been developed to enable you to capture both the quantitative and qualitative \n areas of your CPD activities in a useful friendly interface. It allows for easy capture of \n your reflective learning by answering 4 simple questions, with quick uploading of support\n evidence. Preloaded IHEEM CPD events will exist where applicable (via session code under new CPD).

\n

There is no need to record CPD anywhere else, as MyIHEEM CPD provides you with the unique facility\n to share your CPD record with other professional bodies for their review (via the grant reviewer access tab).

\n

If you have any CPD records in draft status they are shown below. \n To see your full record of CPD go to the My CPD tab.

\n \n
\n
\n \n
\n
\n
\n
\n \n
\n \n );\n}\n\nconst Home = withRouter(_Home);\nexport default Home;\n","import Subject from \"../../modules/data-objects/subject\";\nimport { Route, Switch } from \"react-router-dom\";\nimport React from \"react\";\nimport EditCpd from \"../edit-cpd/edit-cpd\";\nimport AddOrEditCpd from \"../add-or-edit-cpd\";\nimport ReviewerActivityList from \"../activity-list/reviewer-activity-list\";\nimport ActivityListPage from \"../activity-list/activity-list-page\";\nimport ReviewGrantPage from \"../review-grant/review-grant-page\";\nimport Targets from \"../targets\";\nimport UserDetails from \"../user-details\";\nimport Home from \"./home\";\nimport { redirectToLoginPage, getReturnUrl } from \"./app\";\nimport { AppConfig } from \"./app-config\";\nimport * as H from 'history';\n\nexport const appConfigCpd : AppConfig = {\n appDescription: \"MyIHEEM CPD\",\n renderNonLayoutRoutes: (subject:Subject, history:H.History) => [\n \n !subject.isAuthenticated()\n ? redirectToLoginPage(history)\n : \n } />,\n \n !subject.isAuthenticated()\n ? redirectToLoginPage(history)\n : \n } />\n ],\n renderLayoutRoutes: (subject:Subject) =>\n subject.isReviewer()\n ? \n \n \n : \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ,\n getNavEntries: (subject:Subject) => subject.isReviewer()\n ? []\n : [\n { url: \"/\", text: \"Home\" },\n { url: \"/activities\", text: \"My CPD\" },\n { url: \"/reviewgrants\", text: \"Grant reviewer access\" },\n { url: \"/targets\", text: \"Set targets\" },\n { url: \"/user-details\", text: \"Update user details\" },\n ]\n}\n","import React, { useEffect, useState } from \"react\";\nimport ListFolderResult from \"../../modules/data-objects/list-folder-result\";\nimport cupidFetch from \"../../modules/cupid-fetch\";\nimport { Link, useLocation } from \"react-router-dom\";\nimport { getBreadcrumbs } from \"../../modules/utils\";\nimport { LoggedInAs } from \"../utils/logged-in-as\";\nimport Subject from \"../../modules/data-objects/subject\";\nimport { Breadcrumbs, BreadcrumbItem } from 'react-foundation'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { faFolder, faFile } from '@fortawesome/free-regular-svg-icons'\nimport { faLevelUpAlt } from '@fortawesome/free-solid-svg-icons'\n\nclass Props {\n subject!: Subject\n}\n\n/*\n * Note: if there's a path with a % in it, you can navigate it OK in the app but if you try to\n * access it directly from the browser (e.g. make a shortcut or type the URL) you'll get a react\n * error due to this:\n * https://github.com/ReactTraining/react-router/issues/5812\n * https://github.com/ReactTraining/history/issues/505\n * \n * The bug has been closed but there is no easy workaround.\n * The flip side of this is that when we come to make the breadcrumb trail we need to urlDecode\n * the segments for display, but becauase percent isn't encoded properly the decode will fail.\n * hence we need this tryToUrlDecode function \n * \n * Also note that paths with hashes in also fail but that's purely down to the MsGraph SharePoint API\n * and nothing to do with this.\n */\nfunction tryToUrlDecode(s: string) {\n try {\n return decodeURIComponent(s)\n } catch (e) {\n return s\n }\n}\n\n// we need to encode each part of the path but not the slashes\nconst encodePath = (s: string) => s.split(\"/\").map(o => encodeURIComponent(o)).join(\"/\")\n\nexport default function Browse({ subject }: Props) {\n const [listFolderResult, setListFolderResult] = useState(null)\n const location = useLocation()\n const path = location.pathname\n const folderEmpty = listFolderResult && (listFolderResult.files.length + listFolderResult.folders.length === 0)\n\n useEffect(\n () => {\n let isMounted = true\n ; (async () => {\n setListFolderResult(null)\n const result = await cupidFetch(`/api/folder?path=${(path)}`)\n if (result && isMounted) {\n setListFolderResult(result)\n }\n })()\n return () => { isMounted = false }\n },\n [path]\n )\n\n return (\n
\n
\n
\n

Committee document downloads

\n \n
\n
\n
\n
\n

Welcome to MyIHEEM Committees. This area is available for members to view and download documents and meeting papers for all committees and technical platforms they sit on.

\n

If you download any documents please ensure you delete the copy from your computer once you have finished with it.

\n

If you don't see any folders this may be because you are not set up as a committee member within our systems. If you believe you should be, please contact head office for assistance.

\n
\n
\n \n \n Home\n \n {getBreadcrumbs(path).map((o, i) =>\n \n {tryToUrlDecode(o.name)}\n \n )}\n \n
    \n {path !== \"/\" &&\n
  • \n \n \n \n
  • \n }\n {listFolderResult?.folders.map(s =>\n
  • \n \n \n \n {s}\n \n
  • \n )}\n
\n
    \n {folderEmpty &&\n
  • (Empty folder)
  • \n }\n {listFolderResult?.files.map(s =>\n
  • \n \n \n \n {s}\n \n
  • \n )}\n
\n
\n )\n}\n","import { AppConfig } from \"./app-config\";\nimport Subject from \"../../modules/data-objects/subject\";\nimport { Route } from \"react-router-dom\";\nimport React from \"react\";\nimport Browse from \"../committees/browse\";\nimport * as H from 'history';\n\nexport const appConfigCommittees: AppConfig = {\n appDescription: \"MyIHEEM Committees\",\n renderNonLayoutRoutes: (subject: Subject, history: H.History) => [],\n renderLayoutRoutes: (subject: Subject) =>\n \n \n \n ,\n getNavEntries: (subject: Subject) => [],\n}\n","import React, { useState, useEffect } from 'react'\nimport { Switch, Route, Redirect, useHistory } from \"react-router-dom\"\nimport LoginPage from '../authentication/login-page'\nimport ReviewerLogin from '../authentication/reviewer-login'\nimport cupidFetch from '../../modules/cupid-fetch'\nimport Layout from './layout'\nimport SysInfo, { getSysInfoGlobals } from '../../modules/data-objects/sys-info'\nimport Subject, { SubjectDto } from '../../modules/data-objects/subject'\nimport AlertBox from '../utils/alert-box'\nimport { unicode_copyright_sign, unicode_em_space, encodeCurrentUrl } from '../../modules/utils'\nimport * as H from 'history';\nimport { appConfigCpd } from './app-config-cpd'\nimport { appConfigCommittees } from './app-config-committees'\nimport { Helmet } from \"react-helmet\";\n\nexport const appVersion = \"1.0.5\"\nexport const iheemWebSiteUrl = \"https://www.iheem.org.uk\"\n\nexport const redirectToLoginPage = (history: H.History) => ()\n\nexport const getReturnUrl = (history: H.History) => new URLSearchParams(history.location.search).get(\"returnurl\")\n\nconst getAppConfig = () => {\n const app = getSysInfoGlobals().sysInfo?.app\n switch (app) {\n case \"CPD\": return appConfigCpd;\n case \"COMMITTEES\": return appConfigCommittees;\n default: return null;\n }\n}\n\nexport default function App() {\n const history = useHistory()\n const [subject, setSubject] = useState(null)\n const [buildDate, setBuildDate] = useState(\"...\")\n const [nonce, setNonce] = useState(0)\n\n const appConfig = getAppConfig();\n\n useEffect(\n () => {\n const getSubject = async () => {\n const p1 = cupidFetch(\"/api/sysinfo\")\n const p2 = cupidFetch(\"/api/session\")\n const sysInfo = await p1\n if (!sysInfo) return\n const sessionResponse = await p2\n if (!sessionResponse) return\n getSysInfoGlobals().sysInfo = sysInfo\n setBuildDate(sysInfo.buildDate)\n setSubject(new Subject(sessionResponse))\n }\n getSubject()\n },\n [nonce]\n )\n\n const loginCallback = () => {\n setSubject(null)\n setNonce(x => x + 1)\n history.push(getReturnUrl(history) || \"/\")\n }\n\n const separator = `${unicode_em_space}|${unicode_em_space}`\n return (\n <>\n {appConfig && \n {appConfig.appDescription}\n \n \n }\n
\n
\n \n {\n !subject\n ?\n

Loading Please Wait...

\n :\n \n \n {\n subject.isAuthenticated()\n ? \n : \n }\n \n \n \n \n {appConfig!.renderNonLayoutRoutes(subject, history)}\n \n {\n !subject.isAuthenticated()\n ? redirectToLoginPage(history)\n : \n }\n \n \n }\n
\n

 

\n Version {appVersion}\n {separator}\n Build date: {buildDate}\n {separator}\n Copyright {unicode_copyright_sign} Sales Now Ltd.\n
\n
\n
\n \n )\n}\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.0/8 are considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\ntype Config = {\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n};\n\nexport function register(config?: Config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(\n process.env.PUBLIC_URL,\n window.location.href\n );\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl: string, config?: Config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl, {\n headers: { 'Service-Worker': 'script' }\n })\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready\n .then(registration => {\n registration.unregister();\n })\n .catch(error => {\n console.error(error.message);\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './components/app/app';\nimport * as serviceWorker from './serviceWorker';\nimport { BrowserRouter as Router } from \"react-router-dom\";\nimport 'foundation-sites/dist/css/foundation.css';\nimport './app.css';\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n","module.exports = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAB2CAYAAABh7bmNAAAFRGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgZXhpZjpDb2xvclNwYWNlPSIxIgogICBleGlmOlBpeGVsWERpbWVuc2lvbj0iMTgwIgogICBleGlmOlBpeGVsWURpbWVuc2lvbj0iMTE4IgogICBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIgogICBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiCiAgIHRpZmY6SW1hZ2VMZW5ndGg9IjExOCIKICAgdGlmZjpJbWFnZVdpZHRoPSIxODAiCiAgIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiCiAgIHRpZmY6WFJlc29sdXRpb249IjMwMC4wIgogICB0aWZmOllSZXNvbHV0aW9uPSIzMDAuMCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0i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\""],"sourceRoot":""}