\"))\r\n headers[index] = `${header} `;\r\n });\r\n\r\n const headerStyles = tableStyleData.shift();\r\n\r\n return {\r\n headers,\r\n data: tableData,\r\n headerStyles,\r\n dataStyles: tableStyleData,\r\n };\r\n };\r\n\r\n // Helper function to parse HTML string and select elements\r\n const parseAndSelectElements = (htmlString, elementSelector) => {\r\n const doc = new DOMParser().parseFromString(htmlString, \"text/html\");\r\n const elements = doc.querySelectorAll(elementSelector);\r\n\r\n return {\r\n doc,\r\n elements,\r\n };\r\n };\r\n\r\n const parseAndSelectImageElements = (htmlString) => {\r\n const doc = new DOMParser().parseFromString(htmlString, \"text/html\");\r\n const allElements = Array.from(doc.querySelectorAll(\"*\"));\r\n\r\n const selectedElements = allElements.filter((el) => {\r\n if (el.tagName === \"IMG\") {\r\n let parent = el.parentNode;\r\n while (parent) {\r\n if (parent.tagName === \"FIGURE\" && parent.classList.contains(\"image\"))\r\n return false;\r\n\r\n parent = parent.parentNode;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n return el.tagName === \"FIGURE\" && el.classList.contains(\"image\");\r\n });\r\n\r\n return {\r\n doc,\r\n selectedElements,\r\n };\r\n };\r\n\r\n // Function to replace tables\r\n const parseAndReplaceTables = (htmlString, isBigScreen) => {\r\n let { doc, elements: tables } = parseAndSelectElements(htmlString, \"table\");\r\n\r\n for (let i = 0; i < tables.length; i++) {\r\n const parsedTable = parseHTMLTable(tables[i].outerHTML);\r\n\r\n const newTable = generateDivHTML(\r\n parsedTable.headers,\r\n parsedTable.data,\r\n parsedTable.headerStyles,\r\n parsedTable.dataStyles\r\n );\r\n\r\n const newTableElement = new DOMParser().parseFromString(\r\n newTable,\r\n \"text/html\"\r\n ).body.firstChild;\r\n\r\n tables[i].parentNode.replaceChild(newTableElement, tables[i]);\r\n }\r\n\r\n return doc.documentElement.outerHTML;\r\n };\r\n\r\n const replaceOembedWithIFrame = (htmlString) => {\r\n const videoUrlRegEx = /(\\/|%3D|vi*=)([0-9A-z-_]{11})([%#?&]|$)/;\r\n\r\n let { doc, elements: oembeds } = parseAndSelectElements(\r\n htmlString,\r\n \"oembed\"\r\n );\r\n\r\n oembeds.forEach((oembedElement) => {\r\n let url = oembedElement.getAttribute(\"url\");\r\n let match = url.match(videoUrlRegEx);\r\n\r\n let iframe = document.createElement(\"iframe\");\r\n iframe.src = match ? `https://www.youtube.com/embed/${match[2]}` : url;\r\n iframe.width = \"560\";\r\n iframe.height = \"315\";\r\n iframe.frameborder = \"0\";\r\n iframe.allowFullscreen = true;\r\n iframe.allow =\r\n \"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\";\r\n\r\n oembedElement.parentNode.replaceChild(iframe, oembedElement);\r\n });\r\n\r\n return doc.documentElement.outerHTML;\r\n };\r\n\r\n // Function to replace images\r\n const parseAndReplaceImages = (htmlString) => {\r\n let { doc, selectedElements: images } = parseAndSelectImageElements(\r\n htmlString\r\n );\r\n\r\n images.forEach((image) => {\r\n if (image.tagName === \"IMG\") {\r\n let src = image.getAttribute(\"src\");\r\n let className = image.getAttribute(\"class\");\r\n let style = image.getAttribute(\"style\");\r\n\r\n let widthInStyle;\r\n\r\n if (style) {\r\n const widthMatch = style.match(/width:\\s*([^;]+);/);\r\n\r\n if (widthMatch) {\r\n widthInStyle = widthMatch[1];\r\n style = style.replace(widthMatch[0], \"\");\r\n }\r\n }\r\n\r\n let classAttribute = className ? ` class=\"${className}\"` : \"\";\r\n let styleAttribute = style ? ` style=\"${style}\"` : \"\";\r\n\r\n let widthAttribute = \"\";\r\n\r\n if (widthInStyle) {\r\n let percentage = parseFloat(widthInStyle);\r\n\r\n widthAttribute = widthInStyle.includes(\"%\")\r\n ? ` width=\"${\r\n percentage > 99 ? \"100%\" : `${(percentage / 100) * 1350}px`\r\n }\"`\r\n : ` width=\"${widthInStyle}\"`;\r\n }\r\n\r\n const imgElement = ` `;\r\n\r\n image.outerHTML = imgElement;\r\n } else {\r\n let extractedImageFromFigure = image.querySelector(\"img\");\r\n let src = extractedImageFromFigure.getAttribute(\"src\");\r\n let className = image.getAttribute(\"class\");\r\n\r\n if (className) {\r\n if (className === \"image\") className = \"image-style-align-center\";\r\n else\r\n className = className.replace(\r\n \"image \",\r\n \"image-style-align-center \"\r\n );\r\n }\r\n\r\n let style = image.getAttribute(\"style\");\r\n\r\n let widthInStyle;\r\n\r\n if (style) {\r\n const widthMatch = style.match(/width:\\s*([^;]+);/);\r\n\r\n if (widthMatch) {\r\n widthInStyle = widthMatch[1];\r\n style = style.replace(widthMatch[0], \"\");\r\n }\r\n }\r\n\r\n let classAttribute = className ? ` class=\"${className}\"` : \"\";\r\n let styleAttribute = style ? ` style=\"${style}\"` : \"\";\r\n\r\n let widthAttribute = \"\";\r\n\r\n if (widthInStyle) {\r\n let percentage = parseFloat(widthInStyle);\r\n\r\n widthAttribute = widthInStyle.includes(\"%\")\r\n ? ` width=\"${\r\n percentage > 99 ? \"100%\" : `${(percentage / 100) * 1350}px`\r\n }\"`\r\n : ` width=\"${widthInStyle}\"`;\r\n }\r\n\r\n const imgElement = ` `;\r\n\r\n image.outerHTML = imgElement;\r\n }\r\n });\r\n\r\n return doc.documentElement.outerHTML;\r\n };\r\n\r\n const sanitisedHtml = sanitizeHtml(html);\r\n\r\n const isBigScreen = useMediaQuery({\r\n minWidth: 768,\r\n });\r\n\r\n let newHtml = isBigScreen\r\n ? parseAndReplaceImages(sanitisedHtml)\r\n : parseAndReplaceImages(parseAndReplaceTables(sanitisedHtml));\r\n\r\n newHtml = replaceOembedWithIFrame(newHtml);\r\n\r\n return (\r\n // eslint-disable-next-line react/react-in-jsx-scope\r\n
\r\n );\r\n};\r\n\r\nResponsiveHtml.propTypes = {\r\n html: PropTypes.string.isRequired,\r\n};\r\n\r\nexport default ResponsiveHtml;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport CourseContentButtons from \"components/Course-Content-Buttons/Course-Content-Buttons\";\r\nimport CourseContentSections from \"components/Course-Content-Sections/Course-Content-Sections\";\r\nimport ResponsiveHtml from \"components/Common/responsive-html-renderer/responsive-html\";\r\nimport BlockUiFx from \"components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport \"./course-content.scss\";\r\n\r\nclass CourseContent extends Component {\r\n componentDidMount() {\r\n const { match, onLoadSection } = this.props;\r\n onLoadSection(match.params.userCourseId, 1);\r\n }\r\n\r\n componentWillReceiveProps(newProps) {\r\n if (\r\n this.props.courseContent.currentPageIndex !==\r\n newProps.courseContent.currentPageIndex\r\n )\r\n window.scrollTo(0, 0);\r\n }\r\n\r\n render() {\r\n const {\r\n courseName,\r\n currentPageIndex,\r\n totalPages,\r\n totalSections,\r\n currentSection,\r\n currentSectionContent,\r\n isLoading,\r\n } = this.props.courseContent;\r\n const { onNextPage, onPreviousPage, onLoadQuiz } = this.props;\r\n\r\n return (\r\n <>\r\n \r\n {!isLoading ? (\r\n <>\r\n \r\n \r\n \r\n
\r\n {courseName} - Section {currentSection}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n ) : (\r\n
\r\n )}\r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default CourseContent;\r\n","/**\r\n * User Course Service\r\n */\r\nimport HttpClient from \"./../coreLib/http/httpClient\";\r\n\r\nconst UserCourseService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getCourseId = (courseContentToken) =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/courseDetails`);\r\n\r\n const getStatus = (courseContentToken) =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/status`);\r\n\r\n const getCourseDetailsAndStatus = async (courseContentToken) => {\r\n const promise1 = getCourseId(courseContentToken);\r\n const promise2 = getStatus(courseContentToken);\r\n\r\n return await Promise.all([promise1, promise2]).then((values) => {\r\n const result = {\r\n data: {\r\n id: values[0].data.id,\r\n status: values[1].data,\r\n },\r\n };\r\n\r\n return result;\r\n });\r\n };\r\n\r\n const updateRedirectToQuiz = (courseContentToken) =>\r\n httpClient.patch(`/v1/userCourse/${courseContentToken}/quiz/redirect`);\r\n\r\n return {\r\n getCourseId,\r\n getStatus,\r\n getCourseDetailsAndStatus,\r\n updateRedirectToQuiz,\r\n };\r\n};\r\n\r\nexport default UserCourseService;\r\n","import Config from \"config\";\r\nimport HttpClient from \"coreLib/http/httpClient\";\r\nimport CryptoJS from \"crypto-js\";\r\n\r\nconst ApiService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getCourseDetailsAndContents = async (userCourseContentToken) => {\r\n return await httpClient\r\n .get(`/v1/usercourse/${userCourseContentToken}/contents`)\r\n .then((resp) => {\r\n var data = decryptPayload(\r\n resp.data,\r\n Config.crypto_key,\r\n Config.crypto_vector\r\n );\r\n return data;\r\n });\r\n };\r\n\r\n const decryptPayload = (encryptedPayload, secretKey, vector) => {\r\n try {\r\n const ciphertext = CryptoJS.enc.Base64.parse(encryptedPayload);\r\n const key = CryptoJS.enc.Utf8.parse(secretKey);\r\n const initializationVector = CryptoJS.enc.Utf8.parse(vector);\r\n\r\n const decrypted = CryptoJS.AES.decrypt({ ciphertext }, key, {\r\n iv: initializationVector,\r\n mode: CryptoJS.mode.CBC,\r\n padding: CryptoJS.pad.Pkcs7,\r\n });\r\n\r\n const decryptedPayload = decrypted.toString(CryptoJS.enc.Utf8);\r\n const json = JSON.parse(decryptedPayload);\r\n\r\n return json;\r\n } catch (error) {\r\n console.error(\"Error decrypting payload:\", error.message);\r\n }\r\n };\r\n\r\n return {\r\n getCourseDetailsAndContents,\r\n };\r\n};\r\n\r\nexport default ApiService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport UserCourseService from \"./../../../services/user-course-service\";\r\nimport ApiService from \"../services/api-service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadSection = (courseContentToken, allowRedirect, history) => {\r\n return async (dispatch) => {\r\n dispatch(loadSectionRequest());\r\n\r\n const userCourseService = UserCourseService();\r\n\r\n await userCourseService\r\n .getCourseDetailsAndStatus(courseContentToken)\r\n .then(async (resp) => {\r\n const { id, status } = resp.data;\r\n // Redirect logic see #feature-354 and as per Adam's page redirect notes\r\n if (\r\n status.hasCompleted &&\r\n !status.thirdPartyFormCompleted &&\r\n !status.courseExpired\r\n ) {\r\n history.push(`/third-party-form/${courseContentToken}`);\r\n } else if (\r\n status.redirectToQuiz &&\r\n !allowRedirect &&\r\n !status.courseExpired\r\n ) {\r\n history.push(`/course-quiz/${courseContentToken}`);\r\n } else if (status.hasCompleted) {\r\n history.push(`/course-completed/${courseContentToken}`);\r\n } else if (status.isExternalLearning) {\r\n history.push(`/elearning/${courseContentToken}`);\r\n } else if (!status.courseExpired) {\r\n await loadSection(\r\n id,\r\n status.currentSection,\r\n history,\r\n dispatch,\r\n courseContentToken\r\n );\r\n } else {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n }\r\n })\r\n .catch((err) => {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n });\r\n };\r\n};\r\n\r\nconst loadSection = async (\r\n courseId,\r\n sectionId,\r\n history,\r\n dispatch,\r\n userCourseContentToken\r\n) => {\r\n const apiService = ApiService();\r\n\r\n try {\r\n const courseDetailsAndContents = await apiService.getCourseDetailsAndContents(\r\n userCourseContentToken\r\n );\r\n\r\n const selectedSectionId = sectionId === 99 ? 1 : sectionId;\r\n const selectedSection =\r\n courseDetailsAndContents.sections?.find(\r\n (x) => x.sectionId === selectedSectionId\r\n ) ?? null;\r\n\r\n const numberOfSections = courseDetailsAndContents.sections?.length ?? 0;\r\n\r\n dispatch(\r\n loadSectionSuccess(\r\n courseId,\r\n courseDetailsAndContents.courseTitle,\r\n courseDetailsAndContents.sections,\r\n numberOfSections,\r\n sectionId,\r\n 0,\r\n selectedSection.content\r\n )\r\n );\r\n } catch (ex) {\r\n dispatch(loadSectionFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n }\r\n};\r\n\r\nconst loadSectionRequest = () => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_SECTION_REQUEST,\r\n});\r\n\r\nconst loadSectionSuccess = (\r\n courseId,\r\n courseName,\r\n sections,\r\n totalSections,\r\n currentSection,\r\n currentPageIndex,\r\n content\r\n) => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_SECTION_SUCCESS,\r\n payload: {\r\n courseId: courseId,\r\n courseName: courseName,\r\n sections: sections,\r\n totalSections: totalSections,\r\n currentSection: currentSection,\r\n currentPageIndex: currentPageIndex,\r\n content: content,\r\n },\r\n});\r\n\r\nconst loadSectionFailure = () => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_SECTION_FAILURE,\r\n});\r\n\r\nexport const onNextPage = () => ({\r\n type: ActionTypes.COURSE_CONTENT_TOGGLE_NEXT_PAGE,\r\n});\r\n\r\nexport const onPreviousPage = () => ({\r\n type: ActionTypes.COURSE_CONTENT_TOGGLE_PREVIOUS_PAGE,\r\n});\r\n\r\nexport const onLoadQuiz = (courseContentToken, history) => {\r\n return (dispatch) => {\r\n dispatch(loadQuizRequest());\r\n\r\n const userCourseService = UserCourseService();\r\n\r\n userCourseService\r\n .updateRedirectToQuiz(courseContentToken)\r\n .then((resp) => {\r\n dispatch(loadQuizSuccess());\r\n history.push(`/course-quiz/${courseContentToken}/`);\r\n })\r\n .catch((err) => {\r\n dispatch(loadQuizFailure(err));\r\n dispatch(\r\n addNotification(\"Sorry, we couldn't find that quiz.\", \"error\")\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst loadQuizRequest = () => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_QUIZ_REQUEST,\r\n});\r\n\r\nconst loadQuizSuccess = () => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_QUIZ_SUCCESS,\r\n});\r\n\r\nconst loadQuizFailure = (error) => ({\r\n type: ActionTypes.COURSE_CONTENT_LOAD_QUIZ_FAILURE,\r\n payload: error,\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport CourseContent from \"./Course-Content\";\r\nimport { selectCourseContent } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const courseContent = selectCourseContent(state);\r\n\r\n return {\r\n courseContent: courseContent\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onNextPage: () => {\r\n dispatch(actionCreators.onNextPage());\r\n },\r\n onPreviousPage: () => {\r\n dispatch(actionCreators.onPreviousPage());\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n match: ownProps.match\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadSection: courseContentToken => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadSection(\r\n courseContentToken,\r\n stateProps.courseContent.allowRedirect,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n onLoadQuiz: () => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadQuiz(\r\n dispatchProps.match.params.userCourseId,\r\n dispatchProps.history\r\n )\r\n );\r\n }\r\n});\r\n\r\nconst CourseContentContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(CourseContent);\r\n\r\nexport default CourseContentContainer;\r\n","import React from \"react\";\r\nimport { Input, Label } from \"reactstrap\";\r\n\r\nconst CourseQuizQuestionMultiSelect = ({\r\n questionId,\r\n options,\r\n onQuizInputChange\r\n}) => {\r\n const onChange = e => {\r\n const selectedIndex = parseInt(\r\n e.target.attributes.getNamedItem(\"data-index\").value\r\n );\r\n\r\n onQuizInputChange(selectedIndex);\r\n };\r\n\r\n return (\r\n \r\n {options.items.map((value, i) => (\r\n
\r\n \r\n \r\n {value}\r\n \r\n
\r\n ))}\r\n
\r\n );\r\n};\r\n\r\nexport default CourseQuizQuestionMultiSelect;\r\n","import React from \"react\";\r\nimport { Input, Label } from \"reactstrap\";\r\n\r\nconst CourseQuizQuestionDropDown = props => {\r\n const { options, onInputChange } = props;\r\n return (\r\n \r\n \r\n {options.title}\r\n \r\n \r\n onInputChange({\r\n title: options.title,\r\n selectedValue: e.target.value,\r\n selectedIndex: options.items.findIndex(o => o === e.target.value)\r\n })\r\n }\r\n >\r\n - Select - \r\n {options.items.map((item, i) => (\r\n \r\n {item}\r\n \r\n ))}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default CourseQuizQuestionDropDown;\r\n","import React, { Component } from \"react\";\r\nimport CourseQuizQuestionMultiSelect from \"./Course-Quiz-Question-Multi-Select\";\r\nimport CourseQuizQuestionDropDown from \"./Course-Quiz-Question-Drop-Down\";\r\nimport \"./Course-Quiz-Question.scss\";\r\n\r\nclass CourseQuizQuestion extends Component {\r\n getQuizQuestion = (questionId, questionType, options, onQuizInputChange) => {\r\n switch (questionType) {\r\n // questionType: DropDown = 0, MultipleChoice = 1, TrueOrFalse = 2\r\n case 0:\r\n return options.map((option, i) => (\r\n \r\n ));\r\n case 1:\r\n case 2:\r\n return (\r\n \r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n componentWillReceiveProps(newProps) {\r\n // this clears the radiobutton check status.\r\n // for some reason, they won't clear when rendered\r\n // even with different names and ids\r\n if (\r\n newProps.selectedIndex === -1 &&\r\n document.getElementById(\"quizQuestions\")\r\n ) {\r\n const children = document.getElementsByClassName(\"quiz-question-item\");\r\n\r\n for (let i = 0; i < children.length; i++) children[i].checked = false;\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n question,\r\n onQuizInputChange,\r\n selectedIndex,\r\n isFinalQuiz,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n {`${isFinalQuiz ? \"Final Quiz - \" : \"\"}`}Question{\" \"}\r\n {question.questionNo}\r\n
\r\n
\r\n {this.getQuizQuestion(\r\n question.questionId,\r\n question.questionType,\r\n question.options,\r\n onQuizInputChange,\r\n selectedIndex\r\n )}\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default CourseQuizQuestion;\r\n","import React, { Component } from \"react\";\r\nimport { Button } from \"reactstrap\";\r\nimport PageTitle from \"components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport CourseContentSections from \"components/Course-Content-Sections/Course-Content-Sections\";\r\nimport CourseQuizQuestion from \"components/Course-Quiz-Question/Course-Quiz-Question\";\r\nimport BlockUiFx from \"components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport \"./course-quiz.scss\";\r\n\r\nconst OtherButton = (props) => {\r\n const {\r\n courseGuideUrl,\r\n onRedirectToContent,\r\n isFinalQuiz,\r\n userCourseId,\r\n } = props;\r\n\r\n return isFinalQuiz ? (\r\n \r\n Course Guide\r\n \r\n ) : (\r\n onRedirectToContent(userCourseId)}\r\n >\r\n Go Back to the Course Content\r\n \r\n );\r\n};\r\n\r\nclass CourseQuiz extends Component {\r\n componentDidMount() {\r\n const { match, onLoadSection } = this.props;\r\n onLoadSection(match.params.userCourseId);\r\n }\r\n\r\n render() {\r\n const {\r\n courseName,\r\n totalSections,\r\n currentSection,\r\n currentQuestion,\r\n totalQuestions,\r\n currentProgress,\r\n currentQuestionIndex,\r\n showIncorrectAnswer,\r\n selectedIndex,\r\n isLoading,\r\n courseGuideUrl,\r\n isFinalQuiz,\r\n } = this.props.courseQuiz;\r\n\r\n const {\r\n onQuizInputChange,\r\n onSubmitAnswer,\r\n onRedirectToContent,\r\n match,\r\n } = this.props;\r\n\r\n return (\r\n <>\r\n \r\n {!isLoading ? (\r\n <>\r\n \r\n \r\n \r\n
\r\n {courseName} -{\" \"}\r\n {isFinalQuiz\r\n ? \"Final Quiz\"\r\n : `Section ${currentSection} Quiz`}\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n onSubmitAnswer(match.params.userCourseId)\r\n }\r\n >\r\n Continue\r\n \r\n
\r\n
\r\n
\r\n\r\n {showIncorrectAnswer && (\r\n
\r\n Sorry, your answer is incorrect. Please try again.\r\n
\r\n )}\r\n\r\n
\r\n
\r\n \r\n {\" \"}\r\n Question {currentQuestionIndex + 1} of {totalQuestions}\r\n \r\n
\r\n
\r\n
\r\n \r\n >\r\n ) : (\r\n
\r\n )}\r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default CourseQuiz;\r\n","import Config from \"config\";\r\nimport HttpClient from \"coreLib/http/httpClient\";\r\nimport CryptoJS from \"crypto-js\";\r\n\r\nconst ApiService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getCourseDetailsAndQuestions = async (userCourseContentToken) => {\r\n return await httpClient\r\n .get(`/v1/usercourse/${userCourseContentToken}/questions`)\r\n .then((resp) => {\r\n var data = decryptPayload(\r\n resp.data,\r\n Config.crypto_key,\r\n Config.crypto_vector\r\n );\r\n return data;\r\n });\r\n };\r\n\r\n const decryptPayload = (encryptedPayload, secretKey, vector) => {\r\n try {\r\n const ciphertext = CryptoJS.enc.Base64.parse(encryptedPayload);\r\n const key = CryptoJS.enc.Utf8.parse(secretKey);\r\n const initializationVector = CryptoJS.enc.Utf8.parse(vector);\r\n\r\n const decrypted = CryptoJS.AES.decrypt({ ciphertext }, key, {\r\n iv: initializationVector,\r\n mode: CryptoJS.mode.CBC,\r\n padding: CryptoJS.pad.Pkcs7,\r\n });\r\n\r\n const decryptedPayload = decrypted.toString(CryptoJS.enc.Utf8);\r\n const json = JSON.parse(decryptedPayload);\r\n\r\n return json;\r\n } catch (error) {\r\n console.error(\"Error decrypting payload:\", error.message);\r\n }\r\n };\r\n\r\n return {\r\n getCourseDetailsAndQuestions,\r\n };\r\n};\r\n\r\nexport default ApiService;\r\n","/**\r\n * Course Quiz Service\r\n */\r\nimport HttpClient from \"../../../coreLib/http/httpClient\";\r\n\r\nconst CourseQuizService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = (courseContentToken) =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/status`);\r\n\r\n const updateQuizAnswer = (courseContentToken, data) => {\r\n let promiseDeferred = new Promise((resolve, reject) => {\r\n httpClient\r\n .patch(`/v1/userCourse/${courseContentToken}/quiz/answer`, data)\r\n .then((resp) => {\r\n // Get latest status\r\n getStatus(courseContentToken)\r\n .then((resp) => resolve(resp.data))\r\n .catch((err) => reject(err));\r\n })\r\n .catch((err) => reject(err));\r\n });\r\n\r\n return promiseDeferred;\r\n };\r\n\r\n return {\r\n updateQuizAnswer,\r\n };\r\n};\r\n\r\nexport default CourseQuizService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport ApiService from \"../services/api-service\";\r\nimport CourseQuizService from \"../services/course-quiz-service\";\r\nimport UserCourseService from \"./../../../services/user-course-service\";\r\nimport { ActionTypes } from \"./action-types\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadSection = (courseContentToken, history) => async (\r\n dispatch\r\n) => {\r\n dispatch(loadSectionRequest());\r\n\r\n const userCourseService = UserCourseService();\r\n\r\n await userCourseService\r\n .getCourseDetailsAndStatus(courseContentToken)\r\n .then(async (resp) => {\r\n const { id, status } = resp.data;\r\n\r\n // Redirect logic see #feature-354\r\n if (\r\n status.hasCompleted &&\r\n !status.thirdPartyFormCompleted &&\r\n !status.courseExpired\r\n ) {\r\n history.push(`/third-party-form/${courseContentToken}`);\r\n } else if (status.courseCompleted) {\r\n history.push(`/course-completed/${courseContentToken}`);\r\n } else if (!status.redirectToQuiz && !status.courseExpired) {\r\n history.push(`/course-content/${courseContentToken}`);\r\n // } else if (status.courseCompleted || status.surveyCompleted) {\r\n // history.push(`/your-courses`);\r\n } else if (!status.courseExpired) {\r\n let data = await loadSection(\r\n id,\r\n status.currentSection,\r\n status.currentQuestion,\r\n courseContentToken\r\n );\r\n\r\n const {\r\n courseId,\r\n courseTitle,\r\n sectionCount,\r\n sectionId,\r\n questions,\r\n currentQuestion,\r\n courseGuideUrl,\r\n } = data;\r\n\r\n dispatch(\r\n loadSectionSuccess(\r\n courseId,\r\n courseTitle,\r\n sectionCount,\r\n sectionId,\r\n questions,\r\n currentQuestion,\r\n courseGuideUrl\r\n )\r\n );\r\n } else {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n }\r\n })\r\n .catch((err) => {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n });\r\n};\r\n\r\nconst loadSection = async (\r\n courseId,\r\n sectionId,\r\n currentQuestion,\r\n courseContentToken\r\n) => {\r\n const FINAL_QUIZ_SECTION = 99;\r\n const apiService = ApiService();\r\n\r\n const courseDetailsAndQuestions = await apiService.getCourseDetailsAndQuestions(\r\n courseContentToken\r\n );\r\n\r\n let selectedQuestions = courseDetailsAndQuestions.questions.filter((x) => {\r\n return x.courseId === courseId && x.sectionId === sectionId;\r\n });\r\n\r\n let hasFinalQuizSections = courseDetailsAndQuestions.questions.find(\r\n (x) => x.sectionId === FINAL_QUIZ_SECTION\r\n );\r\n\r\n return {\r\n courseId,\r\n courseTitle: courseDetailsAndQuestions.courseTitle,\r\n sectionCount:\r\n courseDetailsAndQuestions.sectionCount - (hasFinalQuizSections ? 1 : 0),\r\n sectionId,\r\n questions: selectedQuestions,\r\n currentQuestion,\r\n courseGuideUrl: `/Print-Course-Content-Guide/${courseContentToken}`,\r\n };\r\n};\r\n\r\nconst loadSectionRequest = () => ({\r\n type: ActionTypes.COURSE_QUIZ_LOAD_SECTION_REQUEST,\r\n});\r\n\r\nconst loadSectionSuccess = (\r\n courseId,\r\n courseName,\r\n totalSections,\r\n currentSection,\r\n questions,\r\n currentQuestion,\r\n courseGuideUrl\r\n) => ({\r\n type: ActionTypes.COURSE_QUIZ_LOAD_SECTION_SUCCESS,\r\n payload: {\r\n courseId,\r\n courseName,\r\n totalSections,\r\n currentSection,\r\n questions,\r\n currentQuestion,\r\n courseGuideUrl,\r\n },\r\n});\r\n\r\nconst loadSectionFailure = () => ({\r\n type: ActionTypes.COURSE_QUIZ_LOAD_SECTION_FAILURE,\r\n});\r\n\r\nexport const onSubmitAnswer = (\r\n courseContentToken,\r\n courseId,\r\n currentQuestion,\r\n selectedIndex,\r\n selectedDropdownIndexes,\r\n history\r\n) => {\r\n return (dispatch) => {\r\n dispatch(submitAnswerRequest());\r\n\r\n // QuestionType supported: DropDown = 0, MultipleChoice = 1, TrueOrFalse = 2\r\n let isCorrect = false;\r\n\r\n if (currentQuestion.questionType === 0) {\r\n // Dropdown question\r\n isCorrect = currentQuestion.options.every((o) => {\r\n let key = o.title.replace(/\\s/g, \"\");\r\n return o.correctIndex === selectedDropdownIndexes[key];\r\n });\r\n } else {\r\n // Radio button list\r\n isCorrect = currentQuestion.options[0].correctIndex === selectedIndex;\r\n }\r\n\r\n if (!isCorrect) {\r\n dispatch(submitAnswerFailure());\r\n return;\r\n }\r\n\r\n const { questionId, sectionId, questionNo } = currentQuestion;\r\n let payload = { questionId, sectionId, questionNo };\r\n\r\n const courseService = CourseQuizService();\r\n courseService\r\n .updateQuizAnswer(courseContentToken, payload)\r\n .then((resp) => {\r\n handleSubmitAnswerRedirects(\r\n courseId,\r\n courseContentToken,\r\n resp,\r\n dispatch,\r\n history\r\n );\r\n })\r\n .catch((err) => {\r\n console.error(err);\r\n dispatch(\r\n addNotification(\"Unable to save quiz answer to server.\", \"error\")\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst handleSubmitAnswerRedirects = async (\r\n courseId,\r\n courseContentToken,\r\n resp,\r\n dispatch,\r\n history\r\n) => {\r\n const {\r\n courseCompleted,\r\n redirectToQuiz,\r\n currentSection,\r\n currentQuestion,\r\n surveyCompleted,\r\n } = resp;\r\n\r\n if (surveyCompleted) {\r\n history.push(`/course-survey/${courseContentToken}`);\r\n } else if (!redirectToQuiz) {\r\n history.push(`/course-content/${courseContentToken}`);\r\n } else if (resp.currentSection === 99) {\r\n // Reload the dataset for section 99 (Final quiz).\r\n let data = await loadSection(\r\n courseId,\r\n currentSection,\r\n currentQuestion,\r\n courseContentToken\r\n );\r\n\r\n dispatch(\r\n loadSectionSuccess(\r\n data.courseId,\r\n data.courseTitle,\r\n data.sectionCount,\r\n data.sectionId,\r\n data.questions,\r\n data.currentQuestion,\r\n data.courseGuideUrl\r\n )\r\n );\r\n }\r\n\r\n dispatch(submitAnswerSuccess(resp));\r\n};\r\n\r\nconst submitAnswerRequest = () => ({\r\n type: ActionTypes.COURSE_QUIZ_SUBMIT_ANSWER_REQUEST,\r\n});\r\n\r\nconst submitAnswerSuccess = (data) => ({\r\n type: ActionTypes.COURSE_QUIZ_SUBMIT_ANSWER_SUCCESS,\r\n payload: data,\r\n});\r\n\r\nconst submitAnswerFailure = () => ({\r\n type: ActionTypes.COURSE_QUIZ_SUBMIT_ANSWER_FAILURE,\r\n});\r\n\r\nexport const onQuizInputChange = (selectedIndex) => {\r\n return (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.COURSE_QUIZ_CHANGE_SELECTED_ANSWER,\r\n payload: {\r\n selectedIndex: selectedIndex,\r\n },\r\n });\r\n };\r\n};\r\n\r\nexport const onQuizDropdownInputChange = (selectedObject) => {\r\n return (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.COURSE_QUIZ_DROPDOWN_CHANGE_SELECTED_ANSWER,\r\n payload: {\r\n selectedObject: selectedObject,\r\n },\r\n });\r\n };\r\n};\r\n\r\nexport const onRedirectToCourseContent = (courseContentToken, history) => {\r\n return (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.COURSE_QUIZ_ALLOW_REDIRECT_TO_COURSE_CONTENT,\r\n });\r\n\r\n history.push(`/course-content/${courseContentToken}`);\r\n };\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport CourseQuiz from \"./Course-Quiz\";\r\nimport { selectCourseQuiz } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport isObject from \"lodash/isObject\";\r\n\r\nfunction mapStateToProps(state) {\r\n const courseQuiz = selectCourseQuiz(state);\r\n\r\n return {\r\n courseQuiz: courseQuiz\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onQuizInputChange: selectedIndex => {\r\n if (!isObject(selectedIndex))\r\n dispatch(actionCreators.onQuizInputChange(selectedIndex));\r\n else dispatch(actionCreators.onQuizDropdownInputChange(selectedIndex));\r\n },\r\n onRedirectToContent: courseContentToken => {\r\n dispatch(\r\n actionCreators.onRedirectToCourseContent(\r\n courseContentToken,\r\n ownProps.history\r\n )\r\n );\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n match: ownProps.match\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadSection: courseContentToken => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadSection(courseContentToken, dispatchProps.history)\r\n );\r\n },\r\n onSubmitAnswer: courseContentToken => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmitAnswer(\r\n courseContentToken,\r\n stateProps.courseQuiz.courseId,\r\n stateProps.courseQuiz.currentQuestion,\r\n stateProps.courseQuiz.selectedIndex,\r\n stateProps.courseQuiz.selectedDropdownIndexes,\r\n dispatchProps.history\r\n )\r\n );\r\n }\r\n});\r\n\r\nconst CourseQuizContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(CourseQuiz);\r\n\r\nexport default CourseQuizContainer;\r\n","import React from \"react\";\r\nimport LinkButton from \"components/link-button/link-button\";\r\nimport WhyTrainWithUsPoints from \"features/why-train-with-us-points/why-train-with-us-points\";\r\nimport ContentSection from \"components/Common/content-section\";\r\n\r\nexport const aboutPages = [\r\n {\r\n pageName: \"about-train-to-gain\",\r\n title:\r\n \"Food Safety Training with Train to Gain Pty Ltd T/A Food Safety Education\",\r\n description: \"\",\r\n noContentSection: true,\r\n content: (\r\n \r\n
\r\n \r\n
\r\n Food Safety Training with Train to Gain Pty Ltd T/A Food Safety\r\n Education\r\n \r\n
\r\n Train to Gain Pty Ltd T/A Food Safety Education is a Nationally\r\n Accredited Registered Training Organisation (RTO provider #\r\n 22361). We have over 30 years of Hospitality and Retail experience\r\n and are 100% Aussie trained and owned.\r\n
\r\n
\r\n
\r\n Our mission is to make your training experience as convenient and\r\n straightforward as possible! Our Food Safety training covers\r\n industries, in the Child Care, Aged Care, Hospitality and Retail\r\n sector. This can all be achieved with the convenience and comfort\r\n of completing your training in your own home or workplace, 100%\r\n online.\r\n
\r\n
\r\n We have scrubbed floors, shaken margaritas and flipped burgers! So\r\n we understand how time poor one can be in the food service\r\n industry. This is why we moved our face to face training model to\r\n online training so that we can provide accredited training to\r\n personnel like you, anywhere, anytime!\r\n
\r\n
\r\n We are a preferred registered training provider with companies\r\n such as Nando's, Mission Australia, Crust Pizza, United\r\n Petroleum, Sodexo, Costco and Spud Bar just to name a few.\r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n \r\n Click here to see our Accreditation to Provide Food Safety\r\n Training\r\n \r\n
\r\n
\r\n \r\n
\r\n \r\n
So Why Train With Us? \r\n \r\n \r\n \r\n
\r\n ),\r\n },\r\n];\r\n","import React from \"react\";\r\nimport { aboutPages } from \"./about-us-page-content\";\r\n\r\nexport const publicPages = [\r\n {\r\n pageName: \"not-found\",\r\n title: \"Page Not Found\",\r\n description: \"\",\r\n content: (\r\n <>\r\n \r\n Food Safety Training with Train to Gain Pty Ltd T/A Food Safety\r\n Education\r\n \r\n >\r\n ),\r\n },\r\n ...aboutPages,\r\n];\r\n","import { publicPages } from \"constants/public-content/index\";\r\n\r\nconst ContentService = () => {\r\n const getContentPage = (pageName, returnUndefinedIfNotFound = false) => {\r\n let page = publicPages.filter((page) => page.pageName === pageName);\r\n\r\n if (returnUndefinedIfNotFound && page.length === 0) return undefined;\r\n\r\n if (page.length === 0)\r\n page = publicPages.filter((page) => page.pageName === \"not-found\");\r\n\r\n return page[0];\r\n };\r\n\r\n return { getContentPage };\r\n};\r\n\r\nexport default ContentService;\r\n","import React, { useEffect, useState } from \"react\";\r\nimport { useLocation } from \"react-router-dom\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport ContentService from \"services/content-service\";\r\n\r\nconst ContentPage = () => {\r\n const location = useLocation();\r\n const [page, setPage] = useState(null);\r\n\r\n useEffect(() => {\r\n const pageName = location.pathname\r\n .replace(new RegExp(\"^[/]+\"), \"\")\r\n .replace(new RegExp(\"[/]+$\"), \"\")\r\n .toLowerCase();\r\n\r\n setPage(ContentService().getContentPage(pageName));\r\n\r\n return () => {\r\n setPage(null);\r\n };\r\n }, [location]);\r\n\r\n return (\r\n <>\r\n {page !== null && (\r\n <>\r\n \r\n {!page.noContentSection && (\r\n \r\n {page.content}
\r\n \r\n )}\r\n {page.noContentSection && page.content}\r\n >\r\n )}\r\n >\r\n );\r\n};\r\n\r\nexport default ContentPage;\r\n","import React from \"react\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport SelectACourse from \"features/select-a-course/select-a-course\";\r\nimport WhyTrainWithUsPoints from \"features/why-train-with-us-points/why-train-with-us-points\";\r\nimport \"./certificates.scss\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\n\r\nconst Certificates = () => {\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
So Why Train With Us? \r\n \r\n \r\n \r\n >\r\n );\r\n};\r\n\r\nexport default Certificates;\r\n","import React from \"react\";\r\nimport { Row, Col, Form, FormGroup } from \"reactstrap\";\r\nimport InputField from \"../Common/Fields/Input-Field\";\r\nimport ButtonFx from \"../Common/Button-Fx/Button-Fx\";\r\nimport {\r\n required,\r\n email,\r\n strongPassword,\r\n} from \"../Common/Fields/Validators/Field-Validators\";\r\nimport \"./register-box.scss\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport formHandler from \"./../Common/Fields/form-handler\";\r\n\r\n// Complex validators\r\nconst validateEmailField = (val) => {\r\n if (required(\"Email\", val)) return required(\"Email\", val);\r\n if (email(val)) return email(val);\r\n\r\n return false;\r\n};\r\n\r\nconst validatePasswordField = (val) => {\r\n if (required(\"Password\", val)) return required(\"Password\", val);\r\n if (strongPassword(val)) return strongPassword(val);\r\n\r\n return false;\r\n};\r\n\r\nconst validateConfirmPasswordField = (password, confirmPwd) => {\r\n if (required(\"Confirm Password\", confirmPwd))\r\n return required(\"Confirm Password\", confirmPwd);\r\n if (password !== confirmPwd) return \"Your passwords do not match.\";\r\n\r\n return false;\r\n};\r\n\r\nconst validateConfirmEmailField = (email, confirmEmail) => {\r\n if (required(\"Confirm Email\", confirmEmail))\r\n return required(\"Confirm Email\", confirmEmail);\r\n if (email !== confirmEmail) return \"Your email addresses do not match.\";\r\n\r\n return false;\r\n};\r\n\r\n//\r\n// Presentation Component\r\n//\r\nconst RegisterBox = (props) => {\r\n const {\r\n firstName,\r\n lastName,\r\n email,\r\n confirmEmail,\r\n password,\r\n confirmPassword,\r\n } = props.registerBox.fields;\r\n const {\r\n courseId,\r\n registerType,\r\n onRegister,\r\n onInputChange,\r\n onFieldError,\r\n isLoading,\r\n noLastName,\r\n toggleNoLastName,\r\n } = props;\r\n\r\n const form = formHandler();\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default RegisterBox;\r\n","/**\r\n * Register API service\r\n */\r\nimport HttpClient from \"../../coreLib/http/httpClient\";\r\n\r\nconst RegisterService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const registerUser = (data, registerType) => {\r\n let payload = {\r\n ...data,\r\n isCorporate: registerType === \"corporate\"\r\n };\r\n\r\n return httpClient.post(\"/v1/accounts\", payload);\r\n };\r\n\r\n return {\r\n registerUser\r\n };\r\n};\r\n\r\nexport default RegisterService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport {\r\n addNotification,\r\n onLoginSuccess,\r\n} from \"../../../redux/system/system-action-creators\";\r\nimport RegisterService from \"../Register-Service\";\r\nimport Auth from \"../../../coreLib/auth/auth\";\r\nimport UserIdentity from \"./../../../coreLib/auth/userIdentity\";\r\n\r\n// =================\r\n// Register\r\n// =================\r\n\r\n// Async\r\nexport const onRegister = (fields, courseId, registerType, history) => {\r\n return (dispatch) => {\r\n const registerService = RegisterService();\r\n dispatch(onRegisterRequest());\r\n\r\n if (fields.lastName === \"\") fields.lastName = fields.firstName;\r\n\r\n registerService\r\n .registerUser(fields, registerType)\r\n .then((resp) => {\r\n dispatch(onRegisterSuccess(resp));\r\n\r\n Auth.setToken(\r\n resp.data.access_token,\r\n resp.data.refresh_token,\r\n resp.data.expires_in\r\n );\r\n\r\n let userIdentity = UserIdentity();\r\n const user = {\r\n // Todo: implement id fetching here\r\n firstName: userIdentity.getFirstName(),\r\n lastName: userIdentity.getLastName(),\r\n userType: userIdentity.userType(),\r\n };\r\n dispatch(onLoginSuccess(user));\r\n\r\n // Redirect\r\n if (registerType === \"student\") {\r\n history.push(`/course-enrolment/${courseId}/step-1/`);\r\n } else {\r\n history.push(\"/Corporate/Purchase-Vouchers/\");\r\n }\r\n })\r\n .catch((err) => {\r\n // Todo: Implement generic error handler in the web template - rcnet\r\n let error = err.response.data && err.response.data.Message;\r\n dispatch(onRegisterFailure());\r\n dispatch(addNotification(error, \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst onRegisterRequest = () => ({\r\n type: ActionTypes.REGISTER_BOX_REGISTER_REQUEST,\r\n});\r\nconst onRegisterSuccess = () => ({\r\n type: ActionTypes.REGISTER_BOX_REGISTER_SUCCESS,\r\n});\r\nconst onRegisterFailure = () => ({\r\n type: ActionTypes.REGISTER_BOX_REGISTER_FAILURE,\r\n});\r\n\r\nexport const toggleNoLastName = () => {\r\n return (dispatch) =>\r\n dispatch({\r\n type: ActionTypes.REGISTER_BOX_FORM_NO_LAST_NAME,\r\n });\r\n};\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.REGISTER_BOX_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport RegisterBox from \"./Register-Box\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport { selectRegisterBox } from \"./redux/reducer\";\r\nimport { onRegister } from \"./redux/action-creators\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport { addNotification } from \"../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const registerBox = selectRegisterBox(state);\r\n\r\n return {\r\n registerBox: registerBox,\r\n isLoading: registerBox.isLoading,\r\n noLastName: registerBox.noLastName,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) => dispatch(addNotification(error, \"Error\")),\r\n toggleNoLastName: () => dispatch(actionCreators.toggleNoLastName()),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n courseId: ownProps.courseId,\r\n registerType: ownProps.registerType,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onRegister: (courseId, registerType) => {\r\n if (validate(stateProps.registerBox)) return;\r\n dispatchProps.dispatch(\r\n onRegister(\r\n stateProps.registerBox.fields,\r\n courseId,\r\n registerType,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps.registerBox);\r\n },\r\n});\r\n\r\nconst validate = (stateProps) => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter((k) => fieldErrors[k]);\r\n const fieldsToCheck = stateProps.noLastName\r\n ? [\"firstName\", \"email\", \"confirmEmail\", \"password\", \"confirmPassword\"]\r\n : [\r\n \"firstName\",\r\n \"lastName\",\r\n \"email\",\r\n \"confirmEmail\",\r\n \"password\",\r\n \"confirmPassword\",\r\n ];\r\n\r\n for (var fld in fieldsToCheck) {\r\n if (!fields[fieldsToCheck[fld]]) return true;\r\n }\r\n\r\n if (!stateProps.noLastName && errMessages.length > 0) return true;\r\n else if (stateProps.noLastName && errMessages.length > 1) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst RegisterBoxContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(RegisterBox);\r\n\r\nexport default withRouter(RegisterBoxContainer);\r\n","import React, { useEffect, useState } from \"react\";\r\nimport { useParams } from \"react-router-dom\";\r\nimport { connect } from \"react-redux\";\r\nimport { Col, Row } from \"reactstrap\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport RegisterBoxContainer from \"components/Register-Box/Register-Box.Container\";\r\nimport CourseService from \"services/course-service\";\r\nimport { selectCertificateRegister } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport \"./certificate-register.scss\";\r\n\r\nconst CertificateRegisterView = () => {\r\n const { courseId } = useParams();\r\n\r\n const courseService = CourseService();\r\n const [course, setCourse] = useState(null);\r\n\r\n useEffect(() => {\r\n const course = courseService.getCourse(courseId);\r\n setCourse(course);\r\n }, [courseService, courseId]);\r\n\r\n return (\r\n <>\r\n {course && (\r\n <>\r\n \r\n \r\n \r\n
Let’s Get Started! \r\n {course.courseTitle} \r\n ${course.courseCost}.00 \r\n {course.validStates && (\r\n {course.validStates} \r\n )}\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n >\r\n )}\r\n >\r\n );\r\n};\r\n\r\nfunction mapStateToProps(state) {\r\n const certificateRegister = selectCertificateRegister(state);\r\n\r\n return {\r\n certificateRegister: certificateRegister,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst CertificateRegister = connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n)(CertificateRegisterView);\r\n\r\nexport default CertificateRegister;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\n//import { addNotification } from \"../../../redux/system/system-action-creators\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\n// export const toggleIsAwesome = () => {\r\n// return dispatch => {\r\n// dispatch(toggleIsAwesomeRequest());\r\n\r\n// let random = Math.floor(Math.random() * 10 + 1);\r\n// const success = random >= 5;\r\n\r\n// if (success) {\r\n// dispatch(toggleIsAwesomeSuccess());\r\n// dispatch(addNotification(\"Success!!\"));\r\n// } else {\r\n// dispatch(toggleIsAwesomeFailure());\r\n// dispatch(addNotification(\"Failure!!\", \"error\")); // error or warning\r\n// }\r\n// };\r\n// };\r\n\r\n// const toggleIsAwesomeRequest = () => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_REQUEST\r\n// });\r\n// const toggleIsAwesomeSuccess = () => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_SUCCESS\r\n// });\r\n// const toggleIsAwesomeFailure = () => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_FAILURE\r\n// });\r\n\r\n// // Async\r\n// export const toggleIsAwesome = data => {\r\n// return dispatch => {\r\n// const myService = MyService();\r\n\r\n// dispatch(toggleIsAwesomeRequest());\r\n\r\n// myService.doSomething(data).then(resp => {\r\n// dispatch(toggleIsAwesomeSuccess(resp));\r\n// });\r\n// };\r\n// };\r\n\r\n// const toggleIsAwesomeRequest = () => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_REQUEST\r\n// });\r\n// const toggleIsAwesomeSuccess = data => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_SUCCESS,\r\n// payload: data\r\n// });\r\n// const toggleIsAwesomeFailure = () => ({\r\n// type: ActionTypes.CERTIFICATE_REGISTER_TOGGLE_IS_AWESOME_FAILURE\r\n// });\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.CERTIFICATE_REGISTER_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import React, { Component } from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport { Table } from \"reactstrap\";\r\nimport DateService from \"../../services/date-service\";\r\nimport CourseService from \"../../services/course-service\";\r\nimport \"./your-courses.scss\";\r\nimport BlockUiFx from \"../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\n\r\nclass YourCourses extends Component {\r\n getCourseActionButtons = (\r\n course,\r\n downloadCertificate,\r\n downloadThirdPartyForm,\r\n downloadTaxInvoice\r\n ) => {\r\n let buttons = [];\r\n\r\n if (\r\n !course.hasCompleted &&\r\n course.completedEnrolment &&\r\n !course.courseExpired &&\r\n !course.isExternalLearning\r\n ) {\r\n let courseButton = (\r\n \r\n Continue Course\r\n \r\n );\r\n\r\n buttons.push(courseButton);\r\n }\r\n\r\n if (\r\n !course.hasCompleted &&\r\n course.completedEnrolment &&\r\n !course.courseExpired &&\r\n course.isExternalLearning\r\n ) {\r\n let courseButton = (\r\n \r\n Continue Course\r\n \r\n );\r\n\r\n buttons.push(courseButton);\r\n }\r\n\r\n if (!course.completedEnrolment && !course.courseExpired) {\r\n let courseButton = (\r\n \r\n Continue Enrolment\r\n \r\n );\r\n\r\n buttons.push(courseButton);\r\n }\r\n\r\n if (course.hasCertificate) {\r\n let certificateButton = (\r\n downloadCertificate(course.id)}\r\n title=\"Download Certificate\"\r\n rel=\"noopener noreferrer\"\r\n >\r\n Download Certificate\r\n \r\n );\r\n\r\n buttons.push(certificateButton);\r\n\r\n let thirdPartyFormButton = (\r\n downloadThirdPartyForm(course.thirdPartyAccessToken)}\r\n title=\"Download Third Party Form\"\r\n rel=\"noopener noreferrer\"\r\n >\r\n Download Third Party Form\r\n \r\n );\r\n\r\n buttons.push(thirdPartyFormButton);\r\n }\r\n if (\r\n course.completedEnrolment &&\r\n (course.hasCertificate || !course.courseExpired)\r\n ) {\r\n let userCourseToken = course.id;\r\n let courseGuideUrl =\r\n (course.courseId === 6 || course.courseId === 8) &&\r\n course.isExternalLearning\r\n ? `/userfiles/files/food-safety-supervisor-nsw-course-guide.pdf`\r\n : `/Print-Course-Content-Guide/${userCourseToken}`;\r\n\r\n let courseGuideButton = (\r\n \r\n Course Guide\r\n \r\n );\r\n buttons.push(courseGuideButton);\r\n }\r\n\r\n if (\r\n !course.completedThirdParty &&\r\n course.completedEnrolment &&\r\n !course.courseExpired\r\n ) {\r\n let thirdPartyButton = (\r\n \r\n Email Third Party Form\r\n \r\n );\r\n\r\n buttons.push(thirdPartyButton);\r\n }\r\n\r\n if (course.invoiceGuid && course.invoiceGuid != null) {\r\n let invoiceButton = (\r\n downloadTaxInvoice(course.invoiceGuid)}\r\n title=\"Download Tax Invoice\"\r\n rel=\"noopener noreferrer\"\r\n >\r\n Tax Invoice\r\n \r\n );\r\n\r\n buttons.push(invoiceButton);\r\n }\r\n\r\n return buttons;\r\n };\r\n\r\n componentDidMount() {\r\n this.props.loadCourses();\r\n }\r\n\r\n render() {\r\n const { courses, isProcessing } = this.props.yourCourses;\r\n const {\r\n downloadCertificate,\r\n downloadThirdPartyForm,\r\n downloadTaxInvoice,\r\n } = this.props;\r\n const dateService = DateService();\r\n const courseService = CourseService();\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n Course \r\n Enrolled On \r\n Status \r\n \r\n \r\n \r\n {courses.map((course, i) => {\r\n const courseDetails = courseService.getCourse(course.courseId);\r\n return (\r\n \r\n \r\n {/* \r\n
\r\n \r\n Course Id \r\n {course.id} \r\n \r\n \r\n Invoice Id \r\n {course.invoiceGuid} \r\n \r\n
\r\n
*/}\r\n \r\n {courseDetails.courseTitle}\r\n {/* ({courseDetails.certificateCodesString}) */}\r\n {(courseDetails.courseId === 6 ||\r\n courseDetails.courseId === 8) &&\r\n course.hasCertificate && (\r\n <>\r\n \r\n The “Download Certificate” button\r\n below allows you to obtain your Nationally\r\n Accredited Statement of Attainment.\r\n \r\n \r\n Your NSW Food Safety Supervisor Certificate\r\n (HARD COPY) will be expressed posted to you\r\n within the next 5-7 days. Please be patient\r\n 😊\r\n
\r\n >\r\n )}\r\n \r\n \r\n {this.getCourseActionButtons(\r\n course,\r\n downloadCertificate,\r\n downloadThirdPartyForm,\r\n downloadTaxInvoice\r\n )}\r\n
\r\n \r\n \r\n {dateService.formatDateFromString(\r\n course.enrolmentDate,\r\n \"DD/MM/YYYY\"\r\n )}\r\n \r\n {course.status} \r\n \r\n );\r\n })}\r\n \r\n
\r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default YourCourses;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport IdentityService from \"../../../coreLib/auth/userIdentity\";\r\nimport HttpService from \"./service\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const toggleIsAwesome = () => {\r\n return (dispatch) => {\r\n dispatch(toggleIsAwesomeRequest());\r\n\r\n let random = Math.floor(Math.random() * 10 + 1);\r\n const success = random >= 5;\r\n\r\n if (success) {\r\n dispatch(toggleIsAwesomeSuccess());\r\n dispatch(addNotification(\"Success!!\"));\r\n } else {\r\n dispatch(toggleIsAwesomeFailure());\r\n dispatch(addNotification(\"Failure!!\", \"error\")); // error or warning\r\n }\r\n };\r\n};\r\n\r\nexport const loadCourses = () => (dispatch) => {\r\n let userId = IdentityService().getUserId();\r\n dispatch(loadCoursesRequest());\r\n HttpService()\r\n .getCourses(userId)\r\n .then((resp) => {\r\n dispatch(loadCoursesRequestSuccess(resp.data));\r\n })\r\n .catch((err) => {\r\n dispatch(loadCoursesRequestFailure());\r\n dispatch(\r\n addNotification(\"There was an issue loading your courses.\", \"warning\")\r\n );\r\n });\r\n};\r\n\r\nexport const downloadTaxInvoice = (invoiceId) => (dispatch) => {\r\n dispatch(downloadTaxInvoiceRequest());\r\n HttpService()\r\n .downloadTaxInvoice(invoiceId)\r\n .then((resp) => {\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"taxinvoice.pdf\");\r\n dispatch(downloadTaxInvoiceSuccess());\r\n dispatch(addNotification(\"Your tax invoice has been downloaded.\"));\r\n })\r\n .catch(() => {\r\n dispatch(downloadTaxInvoiceFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an issue downloading your tax invoice.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nconst downloadTaxInvoiceRequest = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TAX_INVOICE_REQUEST,\r\n});\r\n\r\nconst downloadTaxInvoiceSuccess = (payload) => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TAX_INVOICE_SUCCESS,\r\n});\r\n\r\nconst downloadTaxInvoiceFailure = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TAX_INVOICE_FAILURE,\r\n});\r\n\r\nexport const downloadCertificate = (courseId) => (dispatch) => {\r\n dispatch(downloadCertificateRequest());\r\n HttpService()\r\n .downloadCertificate(courseId)\r\n .then((resp) => {\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"certificate.pdf\");\r\n dispatch(downloadCertificateSuccess());\r\n dispatch(addNotification(\"Your certificate has been downloaded.\"));\r\n })\r\n .catch(() => {\r\n dispatch(downloadCertificateFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an issue downloading your certificate.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nexport const downloadThirdPartyForm = (courseId) => (dispatch) => {\r\n dispatch(downloadTpfRequest());\r\n HttpService()\r\n .downloadThirdPartyForm(courseId)\r\n .then((resp) => {\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"third-party-form.pdf\");\r\n dispatch(downloadTpfSuccess());\r\n dispatch(addNotification(\"Your third party form has been downloaded.\"));\r\n })\r\n .catch(() => {\r\n dispatch(downloadTpfFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an issue downloading your third party form.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nconst downloadCertificateRequest = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_CERTIFICATE_REQUEST,\r\n});\r\n\r\nconst downloadCertificateSuccess = (payload) => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_CERTIFICATE_SUCCESS,\r\n});\r\n\r\nconst downloadCertificateFailure = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_CERTIFICATE_FAILURE,\r\n});\r\n\r\nconst downloadTpfRequest = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TPF_REQUEST,\r\n});\r\n\r\nconst downloadTpfSuccess = (payload) => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TPF_SUCCESS,\r\n});\r\n\r\nconst downloadTpfFailure = () => ({\r\n type: ActionTypes.YOUR_COURSES_DOWNLOAD_TPF_FAILURE,\r\n});\r\n\r\nconst loadCoursesRequest = () => ({\r\n type: ActionTypes.YOUR_COURSES_LOAD_REQUEST,\r\n});\r\n\r\nconst loadCoursesRequestSuccess = (payload) => ({\r\n type: ActionTypes.YOUR_COURSES_LOAD_SUCCESS,\r\n payload,\r\n});\r\n\r\nconst loadCoursesRequestFailure = () => ({\r\n type: ActionTypes.YOUR_COURSES_LOAD_FAILURE,\r\n});\r\n\r\nconst toggleIsAwesomeRequest = () => ({\r\n type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_REQUEST,\r\n});\r\nconst toggleIsAwesomeSuccess = () => ({\r\n type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_SUCCESS,\r\n});\r\nconst toggleIsAwesomeFailure = () => ({\r\n type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_FAILURE,\r\n});\r\n\r\n// // Async\r\n// export const toggleIsAwesome = data => {\r\n// return dispatch => {\r\n// const myService = MyService();\r\n\r\n// dispatch(toggleIsAwesomeRequest());\r\n\r\n// myService.doSomething(data).then(resp => {\r\n// dispatch(toggleIsAwesomeSuccess(resp));\r\n// });\r\n// };\r\n// };\r\n\r\n// const toggleIsAwesomeRequest = () => ({\r\n// type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_REQUEST\r\n// });\r\n// const toggleIsAwesomeSuccess = data => ({\r\n// type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_SUCCESS,\r\n// payload: data\r\n// });\r\n// const toggleIsAwesomeFailure = () => ({\r\n// type: ActionTypes.YOUR_COURSES_TOGGLE_IS_AWESOME_FAILURE\r\n// });\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.YOUR_COURSES_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport YourCourses from \"./Your-Courses\";\r\nimport { selectYourCourses } from \"../../views/Start/redux/reducer\";\r\nimport * as actionCreators from \"../../views/Start/redux/action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const yourCourses = selectYourCourses(state);\r\n return {\r\n yourCourses: yourCourses,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n loadCourses: () => {\r\n dispatch(actionCreators.loadCourses());\r\n },\r\n downloadCertificate: (courseId) => {\r\n dispatch(actionCreators.downloadCertificate(courseId));\r\n },\r\n downloadThirdPartyForm: (thirdPartyAccessToken) => {\r\n dispatch(actionCreators.downloadThirdPartyForm(thirdPartyAccessToken));\r\n },\r\n downloadTaxInvoice: (invoiceId) => {\r\n dispatch(actionCreators.downloadTaxInvoice(invoiceId));\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst YourCoursesContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n)(YourCourses);\r\n\r\nexport default YourCoursesContainer;\r\n","import React from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport { connect } from \"react-redux\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport YourCoursesContainer from \"components/Your-Courses/Your-Courses.Container\";\r\n\r\nconst StartView = ({ isProcessing, hasNswCertificate }) => {\r\n return (\r\n <>\r\n \r\n \r\n \r\n
Your Courses \r\n {!isProcessing && (\r\n
\r\n \r\n Enrol in a New Course\r\n \r\n\r\n {hasNswCertificate && (\r\n \r\n Order a Duplicate Copy NSW FoodSafety Supervisor Certificate\r\n \r\n )}\r\n
\r\n )}\r\n
\r\n
\r\n \r\n >\r\n );\r\n};\r\n\r\nfunction mapStateToProps(state) {\r\n const stateData = state.yourCourses;\r\n return {\r\n isProcessing: stateData.isProcessing,\r\n hasNswCertificate: stateData.hasNswCertificate,\r\n };\r\n}\r\n\r\nconst Start = connect(mapStateToProps)(StartView);\r\n\r\nexport default Start;\r\n","import React from \"react\";\r\nimport { connect } from \"react-redux\";\r\nimport { selectCorporateVouchersRegister } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport \"./corporate-vouchers-register.scss\";\r\nimport GreenTickBalls from \"features/green-tick-balls/green-tick-balls\";\r\nimport { Col, Row } from \"reactstrap\";\r\nimport RegisterBoxContainer from \"components/Register-Box/Register-Box.Container\";\r\n\r\nconst CorporateVouchersRegisterView = () => {\r\n return (\r\n <>\r\n \r\n \r\n \r\n
\r\n Simplify Your Food Safety Training by Ordering Your Course Vouchers\r\n Here\r\n \r\n
\r\n Managing your team’s Food Safety training has never been\r\n easier. Our Business Training Vouchers are designed to take the\r\n hassle out of compliance, offering a streamlined solution for\r\n business owners and managers to ensure their staff is trained and\r\n up-to-date with Food Safety standards.\r\n
\r\n\r\n
\r\n To order course vouchers for your staff , simply\r\n enter your details below to register for access our business portal.\r\n Your vouchers are generated instantly and can be emailed directly to\r\n your staff, allowing them to begin their Food Safety training\r\n immediately!\r\n
\r\n\r\n
\r\n \r\n \r\n Key Benefits of Training With Us\r\n
\r\n \r\n \r\n \r\n \r\n Register for a Business Account\r\n
\r\n \r\n \r\n
\r\n
\r\n How do my staff access their training?\r\n
\r\n
\r\n
\r\n \r\n >\r\n );\r\n};\r\n\r\nfunction mapStateToProps(state) {\r\n const corporateVouchersRegister = selectCorporateVouchersRegister(state);\r\n\r\n return {\r\n corporateVouchersRegister: corporateVouchersRegister,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst CorporateVouchersRegister = connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n)(CorporateVouchersRegisterView);\r\n\r\nexport default CorporateVouchersRegister;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\n//import { addNotification } from \"../../../redux/system/system-action-creators\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\n// export const toggleIsAwesome = () => {\r\n// return dispatch => {\r\n// dispatch(toggleIsAwesomeRequest());\r\n\r\n// let random = Math.floor(Math.random() * 10 + 1);\r\n// const success = random >= 5;\r\n\r\n// if (success) {\r\n// dispatch(toggleIsAwesomeSuccess());\r\n// dispatch(addNotification(\"Success!!\"));\r\n// } else {\r\n// dispatch(toggleIsAwesomeFailure());\r\n// dispatch(addNotification(\"Failure!!\", \"error\")); // error or warning\r\n// }\r\n// };\r\n// };\r\n\r\n// const toggleIsAwesomeRequest = () => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_REQUEST\r\n// });\r\n// const toggleIsAwesomeSuccess = () => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_SUCCESS\r\n// });\r\n// const toggleIsAwesomeFailure = () => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_FAILURE\r\n// });\r\n\r\n// // Async\r\n// export const toggleIsAwesome = data => {\r\n// return dispatch => {\r\n// const myService = MyService();\r\n\r\n// dispatch(toggleIsAwesomeRequest());\r\n\r\n// myService.doSomething(data).then(resp => {\r\n// dispatch(toggleIsAwesomeSuccess(resp));\r\n// });\r\n// };\r\n// };\r\n\r\n// const toggleIsAwesomeRequest = () => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_REQUEST\r\n// });\r\n// const toggleIsAwesomeSuccess = data => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_SUCCESS,\r\n// payload: data\r\n// });\r\n// const toggleIsAwesomeFailure = () => ({\r\n// type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_TOGGLE_IS_AWESOME_FAILURE\r\n// });\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.CORPORATE_VOUCHERS_REGISTER_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import React, { Component } from \"react\";\r\nimport PropTypes from \"prop-types\";\r\nimport { Tooltip } from \"reactstrap\";\r\n\r\nclass ToolTipFx extends Component {\r\n static propTypes = {\r\n placement: PropTypes.string,\r\n target: PropTypes.string\r\n };\r\n\r\n static defaultProps = {\r\n placement: \"auto\"\r\n };\r\n\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n tooltipOpen: false\r\n };\r\n }\r\n\r\n toggle = () => {\r\n this.setState({\r\n tooltipOpen: !this.state.tooltipOpen\r\n });\r\n };\r\n\r\n render() {\r\n return (\r\n \r\n {this.props.children}\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default ToolTipFx;\r\n","/* eslint-disable react-hooks/exhaustive-deps */\r\nimport React, { useEffect } from \"react\";\r\nimport SignatureCanvas from \"react-signature-canvas\";\r\nimport { Row, Col, Button } from \"reactstrap\";\r\nimport \"./signature-pad.scss\";\r\nimport { PropTypes } from \"prop-types\";\r\nimport ToolTipFx from \"./../tooltip/tool-tip-fx\";\r\n\r\nconst SignaturePad = ({\r\n id,\r\n penColor,\r\n padColor,\r\n onChange,\r\n outputType,\r\n initialValue,\r\n padHeight,\r\n padWidth,\r\n isReadonly,\r\n}) => {\r\n let signatureCanvas = {};\r\n\r\n const clearPad = () => {\r\n signatureCanvas.clear();\r\n onChange(\"\");\r\n };\r\n\r\n const getTrimmedCanvasPad = () => {\r\n return signatureCanvas.getTrimmedCanvas().toDataURL(outputType);\r\n };\r\n\r\n const onEnd = () => {\r\n onChange(getTrimmedCanvasPad());\r\n };\r\n\r\n // useEffect(() => {\r\n // if (initialValue) {\r\n // signatureCanvas.clear();\r\n // signatureCanvas.fromDataURL(initialValue);\r\n // }\r\n\r\n // if (isReadonly && signatureCanvas) signatureCanvas.off();\r\n\r\n // return () => {\r\n // if (signatureCanvas) signatureCanvas.off();\r\n // };\r\n // }, []);\r\n\r\n useEffect(() => {\r\n if (initialValue && signatureCanvas.isEmpty()) {\r\n signatureCanvas.clear();\r\n signatureCanvas.fromDataURL(initialValue);\r\n }\r\n\r\n if (isReadonly && signatureCanvas) signatureCanvas.off();\r\n\r\n return () => {\r\n if (signatureCanvas) signatureCanvas.off();\r\n };\r\n }, [initialValue]);\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n {\r\n signatureCanvas = ref;\r\n }}\r\n />\r\n
\r\n \r\n \r\n \r\n x\r\n \r\n \r\n Clear \r\n
\r\n \r\n
\r\n >\r\n );\r\n};\r\n\r\nexport default SignaturePad;\r\n\r\nSignaturePad.propTypes = {\r\n id: PropTypes.string,\r\n onChange: PropTypes.func.isRequired,\r\n penColor: PropTypes.string,\r\n padColor: PropTypes.string,\r\n outputType: PropTypes.string,\r\n padHeight: PropTypes.number,\r\n padWidth: PropTypes.number,\r\n};\r\n\r\nSignaturePad.defaultProps = {\r\n id: \"signaturePad1\",\r\n penColor: \"#000\",\r\n padColor: \"#fff\",\r\n outputType: \"image/png\",\r\n padHeight: 150,\r\n padWidth: 300,\r\n};\r\n","/**\r\n * Presentational Component\r\n *\r\n */\r\nimport React from \"react\";\r\nimport { FormGroup, Label, Input } from \"reactstrap\";\r\nimport InputField from \"../../../components/Common/Fields/Input-Field\";\r\nimport RadioButtonList from \"../../../components/Common/Fields/Radio-Button-List\";\r\nimport SignaturePad from \"../../../components/Common/signature-pad/signature-pad\";\r\n\r\nconst AdditionalInfoForm = (props) => {\r\n const {\r\n onInputChange,\r\n additionalComments,\r\n studentPerformanceSatisfactory,\r\n confirmThirdPartyDeclaration,\r\n signature,\r\n } = props;\r\n\r\n return (\r\n \r\n
\r\n \r\n Overall the student’s performance was\r\n \r\n \r\n \r\n
\r\n \r\n
\r\n \r\n Any additional comments/information\r\n \r\n \r\n \r\n
\r\n \r\n onInputChange({\r\n name: e.target.name,\r\n value: e.target.checked.toString(),\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n I confirm that the information provided in this report, is to the best\r\n of my knowledge, an accurate reflection of the student’s\r\n satisfactory practical skills in the related tasks. I have read this\r\n document in full and understand what is required and I agree to be\r\n contacted if further verification of this report is required.\r\n \r\n \r\n {confirmThirdPartyDeclaration === \"true\" && (\r\n
\r\n \r\n Signature\r\n \r\n \r\n onInputChange({\r\n name: \"signature\",\r\n value: value,\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n )}\r\n\r\n
\r\n You can save your changes at any time, and come back at a later date to\r\n complete this form.\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default AdditionalInfoForm;\r\n","/**\r\n * Presentational component\r\n */\r\nimport React from \"react\";\r\nimport { Button, Form, FormGroup, Label, Row, Col, Input } from \"reactstrap\";\r\nimport InputField from \"./../../../components/Common/Fields/Input-Field\";\r\nimport BlockUiFx from \"./../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport ButtonFx from \"./../../../components/Common/Button-Fx/Button-Fx\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\n\r\nconst validateEmailField = (val) => {\r\n if (validators.required(\"Email\", val))\r\n return validators.required(\"Email\", val);\r\n if (validators.email(val)) return validators.email(val);\r\n\r\n return false;\r\n};\r\n\r\nconst observerNameValidator = (\r\n fieldName,\r\n value,\r\n observerFirstName,\r\n observerLastName,\r\n studentFirstName,\r\n studentLastName,\r\n userType\r\n) => {\r\n if (userType && userType === 3) return false;\r\n\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n\r\n if (\r\n observerFirstName !== \"\" &&\r\n observerLastName !== \"\" &&\r\n studentFirstName !== \"\" &&\r\n studentLastName !== \"\" &&\r\n observerFirstName.toLowerCase() === studentFirstName.toLowerCase() &&\r\n observerLastName.toLowerCase() === studentLastName.toLowerCase()\r\n ) {\r\n return \"Observer Name - this cannot be your own name - your observer may be contacted for verification\";\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst ObserverForm = (props) => {\r\n const {\r\n observerFirstName,\r\n observerLastName,\r\n observerEmail,\r\n onInputChange,\r\n onUpdateDetails,\r\n onEmail,\r\n isLoading,\r\n isUpdateButtonLoading,\r\n onFieldError,\r\n form,\r\n isSampleForm,\r\n isLoggedIn,\r\n firstName,\r\n lastName,\r\n userType,\r\n } = props;\r\n\r\n return (\r\n \r\n \r\n \r\n Observer Name \r\n \r\n \r\n \r\n \r\n observerNameValidator(\r\n \"Observer first name\",\r\n val,\r\n val,\r\n observerLastName,\r\n firstName,\r\n lastName,\r\n userType\r\n )\r\n }\r\n onFieldError={onFieldError}\r\n onChange={onInputChange}\r\n ref={form.add}\r\n />\r\n \r\n \r\n \r\n \r\n \r\n observerNameValidator(\r\n \"Observer last name\",\r\n val,\r\n observerFirstName,\r\n val,\r\n firstName,\r\n lastName,\r\n userType\r\n )\r\n }\r\n onFieldError={onFieldError}\r\n onChange={onInputChange}\r\n ref={form.add}\r\n />\r\n \r\n \r\n
\r\n \r\n \r\n Observer Email \r\n validateEmailField(val)}\r\n onFieldError={onFieldError}\r\n className=\"mxw-400\"\r\n ref={form.add}\r\n />\r\n \r\n {!isSampleForm && isLoggedIn && (\r\n \r\n \r\n form.validate({\r\n validFn: () => onUpdateDetails(),\r\n })\r\n }\r\n disabled={isUpdateButtonLoading}\r\n >\r\n Update Details\r\n \r\n \r\n form.validate({\r\n validFn: () => onEmail(),\r\n })\r\n }\r\n disabled={isUpdateButtonLoading}\r\n >\r\n Email this form to your Observer\r\n \r\n \r\n )}\r\n {isSampleForm && (\r\n \r\n alert(\"This is just a sample form.\")}\r\n disabled={isUpdateButtonLoading}\r\n >\r\n Update Details\r\n \r\n alert(\"This is just a sample form.\")}\r\n disabled={isUpdateButtonLoading}\r\n >\r\n Email this form to your Observer\r\n \r\n \r\n )}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default ObserverForm;\r\n","/**\r\n * Confirm Modal\r\n * Another flavor of Modal dialog\r\n *\r\n * Propeties exposed:\r\n * - title\r\n * - isModalOpen\r\n * - onToggle\r\n *\r\n * Requires to pass objectTag value (id, object to delete etc.)\r\n */\r\nimport React from \"react\";\r\nimport BasicModal from \"./../Basic-Modal/Basic-Modal\";\r\n\r\nconst ConfirmModal = (props) => (\r\n props.onToggle({ type: evt, objectTag: props.objectTag })}\r\n okButtonText={\"Yes\"}\r\n cancelButtonText={\"No\"}\r\n >\r\n {props.children}\r\n \r\n);\r\n\r\nexport default ConfirmModal;\r\n","/**\r\n * Confirm Email Sending\r\n */\r\nimport React from \"react\";\r\nimport ConfirmModal from \"../../../components/Common/Confirm-Modal/Confirm-Modal\";\r\n\r\nconst ConfirmEmailFormSending = (props) => {\r\n return (\r\n \r\n An email will be sent to your observer requesting they complete your third\r\n party form. Are you ready to send it now?\r\n \r\n );\r\n};\r\n\r\nexport default ConfirmEmailFormSending;\r\n","import React from \"react\";\r\nimport BasicModal from \"./../../../components/Common/Basic-Modal/Basic-Modal\";\r\n\r\nconst MessageDialog = props => {\r\n return (\r\n \r\n props.onMessageToggle({ type: evt, objectTag: props.objectTag })\r\n }\r\n okButtonText={\"Ok\"}\r\n showCancel={false}\r\n >\r\n {props.showMessageDialogMessage}\r\n \r\n );\r\n};\r\n\r\nexport default MessageDialog;\r\n","import React, { Component } from \"react\";\r\nimport { Form, FormGroup } from \"reactstrap\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport \"react-datepicker/dist/react-datepicker.css\";\r\nimport InputField from \"../../components/Common/Fields/Input-Field\";\r\nimport RadioButtonList from \"../../components/Common/Fields/Radio-Button-List\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport \"./third-party-form.scss\";\r\nimport AdditionalInfoForm from \"./sub-views/additional-info-form\";\r\nimport ObserverForm from \"./sub-views/observer-form\";\r\nimport ConfirmEmailFormSending from \"./confirm-dialog/Confirm-Email-Form-Sending\";\r\nimport MessageDialog from \"./message-dialog/Message-Dialog\";\r\nimport ButtonFx from \"./../../components/Common/Button-Fx/Button-Fx\";\r\nimport BlockUiFx from \"./../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport formHandler from \"./../../components/Common/Fields/form-handler\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport Auth from \"../../coreLib/auth/auth\";\r\n\r\nclass ThirdPartyForm extends Component {\r\n form = formHandler();\r\n\r\n componentDidMount() {\r\n const { match, onLoadForm, onLoadSampleForm } = this.props;\r\n\r\n if (match.params.userCourseId.toLowerCase() === \"sample\")\r\n onLoadSampleForm(2);\r\n else if (match.params.userCourseId.toLowerCase().startsWith(\"sample-\")) {\r\n onLoadSampleForm(\r\n parseInt(match.params.userCourseId.toLowerCase().replace(\"sample-\", \"\"))\r\n );\r\n } else onLoadForm(match.params.userCourseId);\r\n }\r\n\r\n getUnitsOfCompetency = (certificateCodes, unitOfCompetencies) => {\r\n let units = [];\r\n\r\n for (let i = 0; i < certificateCodes.length; i++) {\r\n units.push(\r\n \r\n {certificateCodes[i]} - {unitOfCompetencies[i]}\r\n \r\n );\r\n }\r\n\r\n return units;\r\n };\r\n\r\n getTaskItems = (tasks, fieldResponses) => {\r\n const getData = (id) => {\r\n return fieldResponses[id] != null ? fieldResponses[id] : undefined;\r\n };\r\n\r\n return tasks.map((task, i) => (\r\n \r\n {task.task} \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ));\r\n };\r\n\r\n getTasksTable = (tasks, fieldResponses) => {\r\n let taskGroups = Array.from(\r\n new Set(\r\n tasks.map((x) => {\r\n return x.taskGroup;\r\n })\r\n )\r\n );\r\n\r\n return taskGroups.map((taskGroup, i) => (\r\n \r\n {i === 0 && (\r\n \r\n \r\n \r\n Does the student consistently meet workplace standards in the\r\n following task area?\r\n \r\n Yes / No \r\n {/* If No, provide a brief explanation */}\r\n Comments (optional) \r\n \r\n \r\n )}\r\n \r\n \r\n {taskGroup} \r\n \r\n {this.getTaskItems(\r\n tasks.filter((x) => x.taskGroup === taskGroup),\r\n fieldResponses\r\n )}\r\n \r\n
\r\n ));\r\n };\r\n\r\n render() {\r\n const {\r\n courseName,\r\n certificateCodes,\r\n unitOfCompetencies,\r\n studentFirstName,\r\n studentLastName,\r\n tasks,\r\n onInputChange,\r\n onUpdateDetails,\r\n onEmail,\r\n isLoading,\r\n isLoadingObserverSection,\r\n isLoadingObserverButton,\r\n isLoadingForSaveProgress,\r\n isLoadingForSubmit,\r\n saveProgress,\r\n submitForm,\r\n validate,\r\n onFieldError,\r\n isSampleForm,\r\n showForm,\r\n thirdPartyFormAdditionalContent,\r\n thirdPartyFormVersion,\r\n } = this.props;\r\n\r\n const {\r\n observerFirstName,\r\n observerLastName,\r\n observerEmail,\r\n additionalComments,\r\n studentPerformanceSatisfactory,\r\n confirmThirdPartyDeclaration,\r\n signature,\r\n } = this.props.fields;\r\n\r\n const { firstName, lastName, userType } = this.props.loginData.loggedInUser;\r\n\r\n let isLoggedIn = Auth.isAuthenticated();\r\n\r\n if (isLoggedIn === undefined) isLoggedIn = false;\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default ThirdPartyForm;\r\n","/**\r\n * Survey Service\r\n */\r\nimport HttpClient from \"./../../coreLib/http/httpClient\";\r\n\r\nconst ThirdPartyFormService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getUserCourseIds = (courseContentToken) =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/ids`);\r\n\r\n const getStatus = (courseContentToken) =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/status`);\r\n\r\n const getThirdPartyForm = (courseContentToken) => {\r\n let promise1 = getUserCourseIds(courseContentToken);\r\n let promise2 = getStatus(courseContentToken);\r\n\r\n let promiseDeferred = new Promise((resolve, reject) => {\r\n //getUserCourseIds(courseContentToken)\r\n Promise.all([promise1, promise2])\r\n .then((resp) => {\r\n // Extract access token\r\n let accessToken = `${courseContentToken.substring(0, 8)}-${\r\n resp[0].data.thirdPartyAccessToken\r\n }`;\r\n\r\n httpClient\r\n .get(`/v1/userCourse/third-party-form/${accessToken}`)\r\n .then((result) => {\r\n resolve({\r\n ...result.data,\r\n courseId: resp[0].data.courseId,\r\n studentFirstName: resp[0].data.firstName,\r\n studentLastName: resp[0].data.lastName,\r\n accessToken,\r\n status: { ...resp[1].data },\r\n isSampleForm: false,\r\n });\r\n })\r\n .catch((e) => reject(e));\r\n })\r\n .catch((err) => reject(err));\r\n });\r\n\r\n return promiseDeferred;\r\n };\r\n\r\n const updateThirdPartyFormObserver = (\r\n accessToken,\r\n data,\r\n sendEmail = false\r\n ) => {\r\n let payload = {\r\n firstName: data.observerFirstName,\r\n lastName: data.observerLastName,\r\n email: data.observerEmail,\r\n sendEmailToObserver: sendEmail,\r\n };\r\n\r\n return httpClient.patch(\r\n `/v1/userCourse/third-party-form/${accessToken}/update-observer`,\r\n payload\r\n );\r\n };\r\n\r\n const saveProgress = (accessToken, payload) =>\r\n httpClient.put(`/v1/userCourse/third-party-form/${accessToken}`, payload);\r\n\r\n return {\r\n getUserCourseIds,\r\n getThirdPartyForm,\r\n updateThirdPartyFormObserver,\r\n saveProgress,\r\n };\r\n};\r\n\r\nexport default ThirdPartyFormService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport CourseService from \"../../../services/course-service\";\r\nimport ThirdPartyFormService from \"./../third-party-form-service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadForm = (courseContentToken, history) => {\r\n return (dispatch) => {\r\n dispatch(LoadFormRequest());\r\n const service = ThirdPartyFormService();\r\n const courseService = CourseService();\r\n\r\n service\r\n .getThirdPartyForm(courseContentToken)\r\n .then((resp) => {\r\n if (resp.status.hasCompleted && resp.status.thirdPartyFormCompleted) {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, this third party form has already been completed.\",\r\n \"error\"\r\n )\r\n );\r\n\r\n history.push(\"/\");\r\n } else if (resp.status.courseExpired) {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, this student's course has expired.\",\r\n \"error\"\r\n )\r\n );\r\n\r\n history.push(\"/\");\r\n } else {\r\n const course = courseService.getCourse(resp.courseId);\r\n const tasks = courseService.getThirdPartyFormTasks(resp.courseId);\r\n\r\n dispatch(\r\n LoadFormSuccess(\r\n course.courseTitle,\r\n course.certificateCodes,\r\n course.unitOfCompetencies,\r\n tasks,\r\n {\r\n thirdPartyFormAdditionalContent:\r\n course.thirdPartyFormAdditionalContent,\r\n ...resp,\r\n }\r\n )\r\n );\r\n }\r\n })\r\n .catch((err) => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n });\r\n };\r\n};\r\n\r\nexport const onLoadSampleForm = (courseId, history) => {\r\n return (dispatch) => {\r\n dispatch(LoadFormRequest());\r\n const courseService = CourseService();\r\n\r\n let course = courseService.getCourse(courseId);\r\n\r\n if (course == null) {\r\n courseId = 2;\r\n course = courseService.getCourse(courseId);\r\n }\r\n\r\n const tasks = courseService.getThirdPartyFormTasks(courseId);\r\n\r\n dispatch(\r\n LoadFormSuccess(\r\n course.courseTitle,\r\n course.certificateCodes,\r\n course.unitOfCompetencies,\r\n tasks,\r\n {\r\n observerFirstName: \"Sample\",\r\n observerLastName: \"Observer\",\r\n observerEmail: \"sample@observer.com.au\",\r\n studentPerformanceSatisfactory: null,\r\n additionalComments: \"\",\r\n confirmThirdPartyDeclaration: null,\r\n thirdPartyFormAdditionalContent:\r\n course.thirdPartyFormAdditionalContent,\r\n thirdPartyFormVersion: course.currentThirdPartyFormVersion,\r\n signature: \"\",\r\n taskResponses: [],\r\n studentFirstName: \"Sample\",\r\n studentLastName: \"Student\",\r\n isSampleForm: true,\r\n showForm: true,\r\n }\r\n )\r\n );\r\n };\r\n};\r\n\r\nconst LoadFormRequest = () => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_LOAD_FORM_REQUEST,\r\n});\r\n\r\nconst LoadFormSuccess = (\r\n courseName,\r\n certificateCodes,\r\n unitOfCompetencies,\r\n tasks,\r\n thirdPartyFormResponses\r\n) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_LOAD_FORM_SUCCESS,\r\n payload: {\r\n courseName: courseName,\r\n certificateCodes: certificateCodes,\r\n unitOfCompetencies: unitOfCompetencies,\r\n tasks: tasks,\r\n thirdPartyFormResponses: thirdPartyFormResponses, // server data\r\n },\r\n});\r\n\r\nconst LoadFormFailure = () => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_LOAD_FORM_FAILURE,\r\n});\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => {\r\n return (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.THIRD_PARTY_FORM_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n });\r\n };\r\n};\r\n\r\n// ------------------------\r\n// Update Third Party Form\r\n// ------------------------\r\n\r\nexport const updateThirdPartyFormObserver = (accessToken, data, history) => {\r\n return (dispatch) => {\r\n dispatch(updateThirdPartyRequest());\r\n const service = ThirdPartyFormService();\r\n\r\n service\r\n .updateThirdPartyFormObserver(accessToken, data)\r\n .then((resp) => {\r\n dispatch(updateThirdPartySuccess());\r\n dispatch(addNotification(\"Successfully saved.\", \"success\"));\r\n })\r\n .catch((err) => {\r\n console.error(err);\r\n dispatch(updateThirdPartyFailure());\r\n dispatch(addNotification(\"Unable to save Third Party Form.\", \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst updateThirdPartyRequest = () => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_OBSERVER_UPDATE_REQUEST,\r\n});\r\n\r\nconst updateThirdPartySuccess = () => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_OBSERVER_UPDATE_SUCCESS,\r\n});\r\n\r\nconst updateThirdPartyFailure = (err) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_OBSERVER_UPDATE_FAILURE,\r\n payload: {\r\n ...err,\r\n },\r\n});\r\n\r\n// ---------------------\r\n// Send Email Confirm\r\n// ---------------------\r\nexport const showConfirmEmailObserver = () => ({\r\n type: ActionTypes.THIRD_PARTY_SHOW_CONFIRM_EMAIL_OBSERVER,\r\n});\r\n\r\nexport const hideConfirmEmailObserver = () => ({\r\n type: ActionTypes.THIRD_PARTY_HIDE_CONFIRM_EMAIL_OBSERVER,\r\n});\r\n\r\nexport const sendEmailAndUpdateThirdPartyForm = (\r\n accessToken,\r\n data,\r\n history\r\n) => {\r\n return (dispatch) => {\r\n dispatch(sendEmailToObserverRequest());\r\n const service = ThirdPartyFormService();\r\n\r\n service\r\n .updateThirdPartyFormObserver(accessToken, data, true)\r\n .then((resp) => {\r\n dispatch(sendEmailToObserverSuccess());\r\n dispatch(\r\n addNotification(\"Third Party Form successfully sent.\", \"success\")\r\n );\r\n })\r\n .catch((err) => {\r\n console.error(err);\r\n dispatch(sendEmailToObserverFailure());\r\n dispatch(\r\n addNotification(\r\n \"Unable to send Third Party Form to Observer.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst sendEmailToObserverRequest = () => ({\r\n type: ActionTypes.THIRD_PARTY_SEND_EMAIL_TO_OBSERVER_REQUEST,\r\n});\r\n\r\nconst sendEmailToObserverSuccess = () => ({\r\n type: ActionTypes.THIRD_PARTY_SEND_EMAIL_TO_OBSERVER_SUCCESS,\r\n});\r\n\r\nconst sendEmailToObserverFailure = () => ({\r\n type: ActionTypes.THIRD_PARTY_SEND_EMAIL_TO_OBSERVER_FAILURE,\r\n});\r\n\r\n// --------------------------\r\n// Save Progress\r\n// --------------------------\r\n\r\nexport const saveProgressThirdPartyForm = (\r\n accessToken,\r\n data,\r\n courseId,\r\n thirdPartyFormVersion,\r\n history,\r\n isSubmit = false\r\n) => {\r\n return (dispatch) => {\r\n dispatch(saveProgressThirdPartyFormRequest(isSubmit));\r\n\r\n const service = ThirdPartyFormService();\r\n const courseService = CourseService();\r\n const tasks = courseService\r\n .getThirdPartyFormTasks(courseId)\r\n .filter((x) => x.version === thirdPartyFormVersion);\r\n\r\n const taskResponses = sanitizeTaskReponses(data);\r\n let result = getTasksToSubmit(tasks, taskResponses);\r\n\r\n const {\r\n observerFirstName,\r\n observerLastName,\r\n observerEmail,\r\n studentPerformanceSatisfactory,\r\n additionalComments,\r\n confirmThirdPartyDeclaration,\r\n signature,\r\n } = data;\r\n\r\n let payload = {\r\n observerFirstName,\r\n observerLastName,\r\n observerEmail,\r\n studentPerformanceSatisfactory: studentPerformanceSatisfactory === \"1\",\r\n additionalComments: additionalComments == null ? \"\" : additionalComments,\r\n confirmThirdPartyDeclaration: confirmThirdPartyDeclaration === \"true\",\r\n taskResponses: [...result],\r\n signature: signature,\r\n };\r\n\r\n service\r\n .saveProgress(accessToken, payload)\r\n .then((resp) => {\r\n dispatch(saveProgressThirdPartyFormSuccess(isSubmit));\r\n dispatch(\r\n addNotification(\"Third Party Form successfully saved.\", \"success\")\r\n );\r\n dispatch(showMessageDialog(resp.data.message));\r\n })\r\n .catch((err) => {\r\n console.error(err);\r\n dispatch(saveProgressThirdPartyFormFailure());\r\n dispatch(addNotification(\"Unable to save Third Party Form.\", \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst saveProgressThirdPartyFormRequest = (isSubmitCaller) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_SAVE_PROGRESS_REQUEST,\r\n payload: {\r\n submitCaller: isSubmitCaller,\r\n },\r\n});\r\n\r\nconst saveProgressThirdPartyFormSuccess = (isSubmitCaller) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_SAVE_PROGRESS_SUCCESS,\r\n payload: {\r\n submitCaller: isSubmitCaller,\r\n },\r\n});\r\n\r\nconst saveProgressThirdPartyFormFailure = (err, isSubmitCaller) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_SAVE_PROGRESS_FAILURE,\r\n payload: {\r\n error: err,\r\n submitCaller: isSubmitCaller,\r\n },\r\n});\r\n\r\n// ---------------------\r\n// Show Message Dialog\r\n// ---------------------\r\nexport const showMessageDialog = (message) => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_SHOW_MESSAGE_DIALOG,\r\n payload: message,\r\n});\r\n\r\nexport const hideMessageDialog = () => ({\r\n type: ActionTypes.THIRD_PARTY_FORM_HIDE_MESSAGE_DIALOG,\r\n});\r\n\r\n// ---------------------\r\n// Helper methods\r\n// ---------------------\r\nconst sanitizeTaskReponses = (taskResponses) => {\r\n let aq = Object.keys(taskResponses)\r\n .filter((k) => k.split(\"-\")[0] === \"task\" && k.split(\"-\")[1] !== \"details\")\r\n .map((k) => {\r\n let resp = taskResponses[k] !== null ? taskResponses[k] === \"true\" : null;\r\n return {\r\n taskId: k.split(\"-\")[1],\r\n response: resp,\r\n comments: taskResponses[`task-details-${k.split(\"-\")[1]}`],\r\n };\r\n });\r\n\r\n return aq;\r\n};\r\n\r\nconst getTasksToSubmit = (tasks, taskResponses) => {\r\n let result = tasks.map((o) => {\r\n let qr = taskResponses.find((x) => x.taskId == o.taskId);\r\n let comments = \"\";\r\n if (qr && qr.comments) comments = qr.comments;\r\n\r\n return {\r\n taskId: o.taskId,\r\n response: qr ? qr.response : null,\r\n comments: comments,\r\n };\r\n });\r\n\r\n return result;\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport ThirdPartyForm from \"./Third-Party-Form\";\r\nimport { selectThirdPartyForm } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport { addNotification } from \"./../../redux/system/system-action-creators\";\r\nimport { selectLoginData } from \"./../../redux/system/login-reducer\";\r\n\r\nfunction mapStateToProps(state) {\r\n const thirdPartyForm = selectThirdPartyForm(state);\r\n const loginData = selectLoginData(state);\r\n\r\n // Redux fields should not be exposed in the view\r\n // create a proper view model props abstraction here to map with.\r\n // Redux fields might change, state Selector and view model props will minimize certain issue.\r\n return {\r\n courseId: thirdPartyForm.courseId,\r\n courseName: thirdPartyForm.courseName,\r\n certificateCodes: thirdPartyForm.certificateCodes,\r\n unitOfCompetencies: thirdPartyForm.unitOfCompetencies,\r\n studentFirstName: thirdPartyForm.studentFirstName,\r\n studentLastName: thirdPartyForm.studentLastName,\r\n tasks: thirdPartyForm.tasks,\r\n accessToken: thirdPartyForm.accessToken,\r\n thirdPartyFormAdditionalContent:\r\n thirdPartyForm.thirdPartyFormAdditionalContent,\r\n thirdPartyFormVersion: thirdPartyForm.thirdPartyFormVersion,\r\n\r\n loginData: loginData,\r\n fields: thirdPartyForm.fields,\r\n fieldErrors: thirdPartyForm.fieldErrors,\r\n\r\n isModalOpen: thirdPartyForm.showConfirmModal,\r\n isLoading: thirdPartyForm.isLoading,\r\n isLoadingObserverSection: thirdPartyForm.isLoadingObserverSection,\r\n isLoadingObserverButton: thirdPartyForm.isLoadingObserverButton,\r\n isLoadingForSaveProgress: thirdPartyForm.isLoadingForSaveProgress,\r\n isLoadingForSubmit: thirdPartyForm.isLoadingForSubmit,\r\n\r\n showMessageDialog: thirdPartyForm.showMessageDialog,\r\n showMessageDialogMessage: thirdPartyForm.showMessageDialogMessage,\r\n\r\n isSampleForm: thirdPartyForm.isSampleForm,\r\n showForm: thirdPartyForm.showForm,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) => dispatch(addNotification(error, \"Error\")),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n match: ownProps.match,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadForm: (courseId) => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadForm(courseId, dispatchProps.history)\r\n );\r\n },\r\n onLoadSampleForm: (courseId) => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadSampleForm(courseId, dispatchProps.history)\r\n );\r\n },\r\n onEmail: (e) => {\r\n dispatchProps.dispatch(actionCreators.showConfirmEmailObserver());\r\n },\r\n onToggle: (evt) => {\r\n if (evt.type === \"ok\") {\r\n if (validate(stateProps)) return;\r\n dispatchProps.dispatch(\r\n actionCreators.sendEmailAndUpdateThirdPartyForm(\r\n stateProps.accessToken,\r\n stateProps.fields,\r\n dispatchProps.history\r\n )\r\n );\r\n } else {\r\n dispatchProps.dispatch(actionCreators.hideConfirmEmailObserver());\r\n }\r\n },\r\n onUpdateDetails: () => {\r\n if (validate(stateProps)) return;\r\n\r\n dispatchProps.dispatch(\r\n actionCreators.updateThirdPartyFormObserver(\r\n stateProps.accessToken,\r\n stateProps.fields,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n saveProgress: () => {\r\n if (validate(stateProps)) return;\r\n\r\n dispatchProps.dispatch(\r\n actionCreators.saveProgressThirdPartyForm(\r\n stateProps.accessToken,\r\n stateProps.fields,\r\n stateProps.courseId,\r\n stateProps.thirdPartyFormVersion,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n submitForm: () => {\r\n //if (validate(stateProps)) return;\r\n\r\n dispatchProps.dispatch(\r\n actionCreators.saveProgressThirdPartyForm(\r\n stateProps.accessToken,\r\n stateProps.fields,\r\n stateProps.courseId,\r\n stateProps.thirdPartyFormVersion,\r\n dispatchProps.history,\r\n true\r\n )\r\n );\r\n },\r\n onMessageToggle: () => {\r\n dispatchProps.dispatch(actionCreators.hideMessageDialog());\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n },\r\n});\r\n\r\n// Obsolete\r\nconst validate = (stateProps) => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter((k) => fieldErrors[k]);\r\n const fieldsToCheck = [\r\n \"observerFirstName\",\r\n \"observerLastName\",\r\n \"observerEmail\",\r\n ];\r\n\r\n for (var fld in fieldsToCheck) {\r\n if (!fields[fieldsToCheck[fld]]) return true;\r\n }\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst ThirdPartyFormContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(ThirdPartyForm);\r\n\r\nexport default ThirdPartyFormContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Row, Col, Button, Form, FormGroup } from \"reactstrap\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport InputField from \"../../components/Common/Fields/Input-Field\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport * as validators from \"../../components/Common/Fields/Validators/Field-Validators\";\r\nimport \"./update-profile.scss\";\r\nimport BockUiFx from \"../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport { Link } from \"react-router-dom\";\r\n\r\n// Combination of validations\r\nconst emailValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (validators.email(value)) return validators.email(value);\r\n\r\n return false;\r\n};\r\n\r\nclass UpdateProfile extends Component {\r\n componentDidMount() {\r\n const { getUserInfo } = this.props;\r\n getUserInfo();\r\n }\r\n\r\n render() {\r\n const { firstName, lastName, email } = this.props.updateProfile.fields;\r\n const { onSubmit, onInputChange, onFieldError, validate } = this.props;\r\n const { isSubmitting } = this.props.updateProfile;\r\n return (\r\n <>\r\n \r\n \r\n
\r\n
\r\n Update Profile \r\n \r\n Updating your details will not change the details on your\r\n existing certificates, or any courses that you have already\r\n enrolled in. If you wish to change your existing certificate or\r\n a course which you are enrolled in, please{\" \"}\r\n contact us.\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default UpdateProfile;\r\n","import HttpClient from \"../../../coreLib//http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getUserInfo = id => {\r\n return httpClient.get(`v1/accounts/${id}`);\r\n };\r\n\r\n const updateProfile = (id, payload) => {\r\n return httpClient.put(`v1/accounts/${id}`, payload);\r\n };\r\n\r\n return {\r\n getUserInfo,\r\n updateProfile\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport * as Constants from \"../../../constants\";\r\nimport HttpService from \"./service\";\r\nimport IdentityService from \"../../../coreLib/auth/userIdentity\";\r\n\r\nexport const onSubmit = (fields) => {\r\n const { firstName, lastName, email } = fields;\r\n\r\n return (dispatch) => {\r\n if (!firstName || firstName === undefined || firstName === \"\") {\r\n dispatch(addNotification(\"First name is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!lastName || lastName === undefined || lastName === \"\") {\r\n dispatch(addNotification(\"Last name is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!email || email === undefined || email === \"\") {\r\n dispatch(addNotification(\"Email address is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!Constants.emailRegex.test(email)) {\r\n dispatch(addNotification(\"Invalid email address.\", \"warning\"));\r\n return;\r\n }\r\n\r\n dispatch(onSubmitStart());\r\n let id = IdentityService().getUserId();\r\n HttpService()\r\n .updateProfile(id, fields)\r\n .then(() => {\r\n dispatch(onSubmitSuccess());\r\n dispatch(addNotification(\"Your profle has been updated successfully.\"));\r\n })\r\n .catch(() => {\r\n dispatch(addNotification(\"Error updating your profile.\", \"warning\"));\r\n dispatch(onSubmitFailure());\r\n });\r\n };\r\n};\r\n\r\nexport const getUserInfo = () => (dispatch) => {\r\n dispatch(onGetUserInfo());\r\n let id = IdentityService().getUserId();\r\n HttpService()\r\n .getUserInfo(id)\r\n .then((resp) => dispatch(onGetUserInfoSuccess(resp.data)))\r\n .catch(() => {\r\n dispatch(addNotification(\"Error loading user details.\", \"warning\"));\r\n dispatch(onGetUserInfoFailure());\r\n });\r\n};\r\n\r\nconst onGetUserInfo = () => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_LOAD,\r\n});\r\n\r\nconst onGetUserInfoSuccess = (payload) => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_LOAD_SUCCESS,\r\n payload,\r\n});\r\n\r\nconst onGetUserInfoFailure = () => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_LOAD_FAILURE,\r\n});\r\n\r\nconst onSubmitStart = () => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_SUBMIT,\r\n});\r\n\r\nconst onSubmitSuccess = (payload) => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_SUBMIT_SUCCESS,\r\n payload,\r\n});\r\n\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.UPDATE_PROFILE_ON_SUBMIT_FAILURE,\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.UPDATE_PROFILE_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport UpdateProfile from \"./Update-Profile\";\r\nimport { selectUpdateProfile } from \"./redux/reducer\";\r\nimport { onSubmit, getUserInfo } from \"./redux/action-creators\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport * as sysActionCreators from \"../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const updateProfile = selectUpdateProfile(state);\r\n return {\r\n updateProfile: updateProfile,\r\n fields: updateProfile.fields,\r\n fieldErrors: updateProfile.fieldErrors,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onSubmit: () => {\r\n // Validation code here\r\n if (validate(stateProps)) return;\r\n dispatchProps.dispatch(onSubmit(stateProps.updateProfile.fields));\r\n },\r\n getUserInfo: () => {\r\n dispatchProps.dispatch(getUserInfo());\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n },\r\n});\r\n\r\nconst validate = (stateProps) => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter((k) => fieldErrors[k]);\r\n\r\n if (!fields.firstName) return true;\r\n if (!fields.lastName) return true;\r\n if (!fields.email) return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst UpdateProfileContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(UpdateProfile);\r\n\r\nexport default UpdateProfileContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Row, Col, Button, Form, FormGroup, Label } from \"reactstrap\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport InputField from \"../../components/Common/Fields/Input-Field\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport * as validators from \"../../components/Common/Fields/Validators/Field-Validators\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\nimport BlockUiFx from \"../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\n\r\nclass ChnagePassword extends Component {\r\n passwordValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (value.length < 8) return validators.min(value, \"Password\", 8);\r\n if (value.length > 50) return validators.max(value, \"Password\", 50);\r\n if (!/^(?=.*[!@#$&*0-9])(?=.*[a-z].*[a-z].*[a-z]).{8,50}$/.test(value)) {\r\n return validators.meessage(\r\n \"Password must have at least 1 special character or a number.\"\r\n );\r\n }\r\n\r\n return false;\r\n };\r\n\r\n confirmPasswordValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (this.props.changePassword.fields.password != value)\r\n return validators.meessage(\r\n \"Password and confirm confirm password must match\"\r\n );\r\n return false;\r\n };\r\n\r\n render() {\r\n const {\r\n password,\r\n oldPassword,\r\n confirmPassword,\r\n } = this.props.changePassword.fields;\r\n const { isSubmitting, isSubmitted } = this.props.changePassword;\r\n const { onSubmit, onInputChange, onFieldError, validate } = this.props;\r\n return (\r\n <>\r\n \r\n \r\n Change Password \r\n \r\n \r\n Your password has been successfully changed. \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default ChnagePassword;\r\n","import HttpClient from \"../../../coreLib//http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const changePassword = (id, payload) => {\r\n return httpClient.patch(`v1/accounts/${id}/password/change`, payload);\r\n };\r\n\r\n return {\r\n changePassword\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport HttpService from \"./service\";\r\n\r\nexport const onSubmit = (id, fields) => {\r\n const { oldPassword, password, confirmPassword } = fields;\r\n\r\n return dispatch => {\r\n if (!oldPassword || oldPassword === undefined || oldPassword === \"\") {\r\n dispatch(addNotification(\"Old password is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!password || password === undefined || password === \"\") {\r\n dispatch(addNotification(\"Password is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (\r\n !confirmPassword ||\r\n confirmPassword === undefined ||\r\n confirmPassword === \"\"\r\n ) {\r\n dispatch(addNotification(\"Confirm Password is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n dispatch(onSubmitRequest());\r\n HttpService()\r\n .changePassword(id, fields)\r\n .then(() => dispatch(onSubmitSuccess()))\r\n .catch(err => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\r\n err.response.data.Message\r\n ? err.response.data.Message\r\n : \"Changing of password failed.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.CHANGE_PASSWORD_ON_SUBMIT\r\n});\r\n\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.CHANGE_PASSWORD_ON_SUCCESS\r\n});\r\n\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.CHANGE_PASSWORD_ON_FAILURE\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.CHANGE_PASSWORD_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport ChangePassword from \"./Change-Password\";\r\nimport { selectChangePassword } from \"./redux/reducer\";\r\nimport { selectLoginData } from \"../../redux/system/login-reducer\";\r\nimport { onSubmit } from \"./redux/action-creators\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport * as sysActionCreators from \"../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const changePassword = selectChangePassword(state);\r\n const loginData = selectLoginData(state);\r\n return {\r\n changePassword: changePassword,\r\n fields: changePassword.fields,\r\n loginData: loginData,\r\n fieldErrors: changePassword.fieldErrors\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: error =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n dispatch: dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onSubmit: () => {\r\n // Validation code here\r\n if (validate(stateProps)) return;\r\n dispatchProps.dispatch(\r\n onSubmit(\r\n stateProps.loginData.loggedInUser.id,\r\n stateProps.changePassword.fields\r\n )\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n }\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n\r\n if (!fields.password) return true;\r\n if (!fields.oldPassword) return true;\r\n if (!fields.confirmPassword) return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst ChangePasswordContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(ChangePassword);\r\n\r\nexport default ChangePasswordContainer;\r\n","import React from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\n\r\nconst ArrowLinkButton = ({ to, title, showAsBlue, showDownArrow }) => {\r\n return (\r\n \r\n {title}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ArrowLinkButton;\r\n","/**\r\n * Forbidden page (HTTP 403)\r\n */\r\nimport React, { Component } from \"react\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport ArrowLinkButton from \"../../../components/Arrow-Link-Button/Arrow-Link-Button\";\r\n\r\nclass Error403 extends Component {\r\n state = {};\r\n render() {\r\n return (\r\n <>\r\n \r\n 403 - Access Forbidden... \r\n \r\n You do not have enough permission to access the page.\r\n \r\n \r\n Contact your system administrator.\r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default Error403;\r\n","import React from \"react\";\r\nimport { Row, Col, Form, FormGroup } from \"reactstrap\";\r\nimport InputField from \"../Common/Fields/Input-Field\";\r\nimport ButtonFx from \"../Common/Button-Fx/Button-Fx\";\r\nimport * as Constants from \"../../constants\";\r\nimport { required, email } from \"../Common/Fields/Validators/Field-Validators\";\r\nimport formHandler from \"./../Common/Fields/form-handler\";\r\n//import \"./register-box.scss\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\n\r\n// Custom validators\r\nconst validateEmailField = val => {\r\n if (required(\"Email\", val)) return required(\"Email\", val);\r\n if (email(val)) return email(val);\r\n\r\n return false;\r\n};\r\n\r\n//\r\n// Presentation Component\r\n//\r\nconst ForgotPassword = props => {\r\n const { email } = props.fields;\r\n const {\r\n onInputChange,\r\n onFieldError,\r\n onResetPassword,\r\n validate,\r\n isLoading,\r\n isSubmitted,\r\n submittedTo\r\n } = props;\r\n\r\n const form = formHandler();\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default ForgotPassword;\r\n","/**\r\n * Forgot Password API service\r\n */\r\nimport HttpClient from \"../../coreLib/http/httpClient\";\r\n\r\nconst ForgotPasswordService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const requestResetPassword = email =>\r\n httpClient.patch(`/v1/accounts/password/reset/request`, {\r\n username: email\r\n });\r\n\r\n return {\r\n requestResetPassword\r\n };\r\n};\r\n\r\nexport default ForgotPasswordService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport ForgotPasswordService from \"../Forgot-Password-Service\";\r\n\r\n// =================\r\n// Reset Password\r\n// =================\r\n\r\n// Async\r\nexport const onRequestResetPassword = email => {\r\n return dispatch => {\r\n const service = ForgotPasswordService();\r\n dispatch(onRequestResetPasswordRequest());\r\n\r\n service\r\n .requestResetPassword(email)\r\n .then(resp => {\r\n dispatch(onRequestResetPasswordSuccess(resp));\r\n })\r\n .catch(err => {\r\n // Todo: Implement generic error handler in the web template - rcnet\r\n let error = err.response.data && err.response.data.Message;\r\n dispatch(onRequestResetPasswordFailure());\r\n dispatch(addNotification(error, \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst onRequestResetPasswordRequest = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_RESET_REQUEST\r\n});\r\nconst onRequestResetPasswordSuccess = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_RESET_SUCCESS\r\n});\r\nconst onRequestResetPasswordFailure = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_RESET_FAILURE\r\n});\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.FORGOT_PASSWORD_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport ForgotPassword from \"./Forgot-Password\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport { selectForgotPassword } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport { addNotification } from \"../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const stateData = selectForgotPassword(state);\r\n\r\n return {\r\n fields: stateData.fields,\r\n fieldErrors: stateData.fieldErrors,\r\n isLoading: stateData.isLoading,\r\n isSubmitted: stateData.isSubmitted,\r\n submittedTo: stateData.submittedTo\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: error => dispatch(addNotification(error, \"Error\")),\r\n dispatch: dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onResetPassword: () => {\r\n if (validate(stateProps)) return;\r\n dispatchProps.dispatch(\r\n actionCreators.onRequestResetPassword(stateProps.fields.email)\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n }\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n const fieldsToCheck = [\"email\"];\r\n\r\n for (var fld in fieldsToCheck) {\r\n if (!fields[fieldsToCheck[fld]]) return true;\r\n }\r\n\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst ForgotPasswordContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(ForgotPassword);\r\n\r\nexport default withRouter(ForgotPasswordContainer);\r\n","import React from \"react\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport ForgotPasswordContainer from \"../../components/Forgot-Password/Forgot-Password.Container\";\r\n\r\nconst ForgotPasswordView = () => (\r\n <>\r\n \r\n \r\n \r\n
\r\n
Forgot Password \r\n \r\n \r\n
\r\n \r\n >\r\n);\r\n\r\nexport default ForgotPasswordView;\r\n","import React from \"react\";\r\nimport { Row, Col, Form, FormGroup } from \"reactstrap\";\r\nimport InputField from \"../Common/Fields/Input-Field\";\r\nimport ButtonFx from \"../Common/Button-Fx/Button-Fx\";\r\nimport * as Constants from \"../../constants\";\r\nimport {\r\n required,\r\n strongPassword\r\n} from \"../Common/Fields/Validators/Field-Validators\";\r\nimport formHandler from \"./../Common/Fields/form-handler\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\n\r\n// Custom validators\r\nconst validatePasswordField = val => {\r\n if (required(\"Password\", val)) return required(\"Password\", val);\r\n if (strongPassword(val)) return strongPassword(val);\r\n\r\n return false;\r\n};\r\n\r\nconst validateConfirmPasswordField = (password, confirmPwd) => {\r\n if (required(\"Confirm Password\", confirmPwd))\r\n return required(\"Confirm Password\", confirmPwd);\r\n if (password !== confirmPwd) return \"Your passwords do not match.\";\r\n\r\n return false;\r\n};\r\n\r\n//\r\n// Presentation Component\r\n//\r\nconst ResetPassword = props => {\r\n const { password, confirmPassword } = props.fields;\r\n const { onInputChange, onFieldError, onResetPassword, isLoading } = props;\r\n\r\n const form = formHandler();\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default ResetPassword;\r\n","/**\r\n * Forgot Password API service\r\n */\r\nimport HttpClient from \"../../coreLib/http/httpClient\";\r\n\r\nconst ResetPasswordService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const resetPassword = (data, resetToken) =>\r\n httpClient.post(`/v1/accounts/password/reset`, {\r\n ...data,\r\n resetToken\r\n });\r\n\r\n return {\r\n resetPassword\r\n };\r\n};\r\n\r\nexport default ResetPasswordService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport {\r\n addNotification,\r\n onLoginSuccess,\r\n} from \"../../../redux/system/system-action-creators\";\r\nimport ResetPasswordService from \"../Reset-Password-Service\";\r\nimport Auth from \"../../../coreLib/auth/auth\";\r\nimport UserIdentity from \"./../../../coreLib/auth/userIdentity\";\r\n\r\n// =================\r\n// Reset Password\r\n// =================\r\n\r\n// Async\r\nexport const onResetPassword = (data, resetToken, history) => {\r\n return (dispatch) => {\r\n const service = ResetPasswordService();\r\n dispatch(onResetPasswordRequest());\r\n\r\n service\r\n .resetPassword(data, resetToken)\r\n .then((resp) => {\r\n dispatch(onResetPasswordSuccess(resp));\r\n\r\n Auth.setToken(\r\n resp.data.access_token,\r\n resp.data.refresh_token,\r\n resp.data.expires_in\r\n );\r\n\r\n let userIdentity = UserIdentity();\r\n const user = {\r\n // Todo: implement id fetching here\r\n firstName: userIdentity.getFirstName(),\r\n lastName: userIdentity.getLastName(),\r\n userType: userIdentity.userType(),\r\n };\r\n dispatch(onLoginSuccess(user));\r\n\r\n // Redirect to home\r\n history.push(\"/\");\r\n })\r\n .catch((err) => {\r\n // Todo: Implement generic error handler in the web template - rcnet\r\n let error = err.response.data && err.response.data.Message;\r\n dispatch(onResetPasswordFailure());\r\n dispatch(addNotification(error, \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst onResetPasswordRequest = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_APPLY_RESET_REQUEST,\r\n});\r\nconst onResetPasswordSuccess = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_APPLY_RESET_SUCCESS,\r\n});\r\nconst onResetPasswordFailure = () => ({\r\n type: ActionTypes.FORGOT_PASSWORD_APPLY_RESET_FAILURE,\r\n});\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.FORGOT_PASSWORD_APPLY_RESET_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport ResetPassword from \"./Reset-Password\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport { selectResetPassword } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport { addNotification } from \"../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const stateData = selectResetPassword(state);\r\n\r\n return {\r\n fields: stateData.fields,\r\n fieldErrors: stateData.fieldErrors,\r\n isLoading: stateData.isLoading\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: error => dispatch(addNotification(error, \"Error\")),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n resetToken: ownProps.match.params.resetToken\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onResetPassword: () => {\r\n if (validate(stateProps)) return;\r\n dispatchProps.dispatch(\r\n actionCreators.onResetPassword(\r\n stateProps.fields,\r\n dispatchProps.resetToken,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n }\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n //const fieldsToCheck = [\"password\", \"confirmPassword\"];\r\n\r\n // for (var fld in fieldsToCheck) {\r\n // if (!fields[fieldsToCheck[fld]]) return true;\r\n // }\r\n if (!fields.password) return true;\r\n if (!fields.confirmPassword) return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst ResetPasswordContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(ResetPassword);\r\n\r\nexport default withRouter(ResetPasswordContainer);\r\n","import React from \"react\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport ResetPasswordContainer from \"../../components/Reset-Password/Reset-Password.Container\";\r\n\r\nconst ResetPasswordView = () => (\r\n <>\r\n \r\n \r\n \r\n
\r\n
Reset Password \r\n \r\n \r\n
\r\n \r\n >\r\n);\r\n\r\nexport default ResetPasswordView;\r\n","import HttpClient from \"../../../coreLib//http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const submit = payload => {\r\n return httpClient.post(\"v1/userCourse/nsw-reprint\", payload);\r\n };\r\n\r\n return {\r\n submit\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import IdentityService from \"../../../coreLib/auth/userIdentity\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport { ActionTypes } from \"./action-types\";\r\nimport Service from \"./service\";\r\n\r\nexport const init = () => ({\r\n type: ActionTypes.NSW_REPRINT_INIT,\r\n});\r\n\r\nexport const setEmail = () => (dispatch) => {\r\n let email = IdentityService().getEmail();\r\n dispatch(formInputChange(\"email\", email));\r\n};\r\n\r\nexport const onCreditCardInputChange = (card) => (dispatch) => {\r\n const { field, value, meta } = card;\r\n dispatch(formInputChange(field, value));\r\n let isCreditCardValid = Object.values(meta).every((m) => m === undefined);\r\n dispatch(setCardValidity(isCreditCardValid));\r\n};\r\n\r\nconst setCardValidity = (value) => ({\r\n type: ActionTypes.NSW_REPRINT_SET_CARD_VALIDITY,\r\n payload: value,\r\n});\r\n\r\nexport const updateAutocompleteAddress = (data) => {\r\n return (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.NSW_REPRINT_AUTOCOMPLETE_ADDRESS_UPDATE,\r\n payload: data,\r\n });\r\n };\r\n};\r\n\r\nexport const toggleManualAddressEntry = () => ({\r\n type: ActionTypes.NSW_REPRINT_TOGGLE_MANUAL_ADDRESS_ENTRY,\r\n});\r\n\r\nexport const togglePromoCodeEntry = () => ({\r\n type: ActionTypes.NSW_REPRINT_TOGGLE_PROMO_CODE_ENTRY,\r\n});\r\n\r\nconst showManualAddressEntry = () => ({\r\n type: ActionTypes.NSW_REPRINT_SHOW_MANUAL_ADDRESS_ENTRY,\r\n});\r\n\r\nexport const clearAddress = () => ({\r\n type: ActionTypes.NSW_REPRINT_CLEAR_ADDRESS,\r\n});\r\n\r\nexport const toggleShowConfirmPopup = () => ({\r\n type: ActionTypes.NSW_REPRINT_SHOW_CONFIRM_POPUP,\r\n});\r\n\r\nexport const onSubmit = (stateProps, fields, history) => {\r\n const {\r\n streetNumber,\r\n streetName,\r\n city,\r\n state,\r\n postcode,\r\n email,\r\n cardNumber,\r\n cardExpiryDate,\r\n cardName,\r\n cardCvc,\r\n promoCode,\r\n } = fields;\r\n return (dispatch, getState) => {\r\n const { hasPromoCode } = stateProps;\r\n const { addressEntry } = getState().nswReprint;\r\n\r\n if (!addressEntry.enterAddressManually && !addressEntry.fullAddress) {\r\n dispatch(addNotification(\"Address is required\", \"error\"));\r\n return true;\r\n }\r\n\r\n if (!streetNumber || streetNumber === undefined || streetNumber === \"\") {\r\n dispatch(addNotification(\"Street number is required.\", \"warning\"));\r\n dispatch(showManualAddressEntry());\r\n return;\r\n }\r\n\r\n if (!streetName || streetName === undefined || streetName === \"\") {\r\n dispatch(addNotification(\"Street name is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!city || city === undefined || city === \"\") {\r\n dispatch(addNotification(\"City is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!state || state === undefined || state === \"\") {\r\n dispatch(addNotification(\"State is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!postcode || postcode === undefined || postcode === \"\") {\r\n dispatch(addNotification(\"Post code is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!email || email === undefined || email === \"\") {\r\n dispatch(addNotification(\"Email address code is required.\", \"warning\"));\r\n return;\r\n }\r\n\r\n if (!cardName) {\r\n dispatch(addNotification(\"Please enter a card name\", \"error\"));\r\n return true;\r\n }\r\n if (!cardNumber || !cardExpiryDate || !cardCvc) {\r\n dispatch(\r\n addNotification(\"Please enter a valid credit card details\", \"error\")\r\n );\r\n return true;\r\n }\r\n // Submit Validation\r\n\r\n let model = {\r\n ...fields,\r\n cardExpiryDate: fields.cardExpiryDate.replace(/ /g, \"\"),\r\n };\r\n\r\n dispatch(onSubmitRequest());\r\n Service()\r\n .submit(model)\r\n .then((resp) => {\r\n const { purchaseSuccessful, errorMessage } = resp.data;\r\n if (!purchaseSuccessful) {\r\n dispatch(onSubmitFailure());\r\n dispatch(addNotification(errorMessage, \"warning\"));\r\n } else {\r\n dispatch(onSubmitSuccess());\r\n }\r\n })\r\n .catch((err) => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\r\n err.response.data.Message\r\n ? err.response.data.Message\r\n : err.response.data.title\r\n ? err.response.data.title\r\n : \"There was an issue submitting the form\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.NSW_REPRINT_SUBMIT_ENROLMENT_REQUEST,\r\n});\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.NSW_REPRINT_SUBMIT_ENROLMENT_SUCCESS,\r\n});\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.NSW_REPRINT_SUBMIT_ENROLMENT_FAILURE,\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.NSW_REPRINT_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n","import isNil from \"lodash/isNil\";\r\nimport React, { Component } from \"react\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport { Link } from \"react-router-dom\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\nimport {\r\n Button,\r\n Form,\r\n FormGroup,\r\n Label,\r\n Modal,\r\n ModalBody,\r\n ModalFooter,\r\n ModalHeader,\r\n} from \"reactstrap\";\r\nimport \"../../assets/styles/enrolment-forms.scss\";\r\nimport BlockUiFx from \"../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport ButtonFx from \"../../components/Common/Button-Fx/Button-Fx\";\r\nimport formHandler from \"../../components/Common/Fields/form-handler\";\r\nimport InputField from \"../../components/Common/Fields/Input-Field\";\r\nimport PaymentInputs from \"../../components/Common/Fields/Payment-Inputs\";\r\nimport * as validators from \"../../components/Common/Fields/Validators/Field-Validators\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport LoqateAddressField from \"./../../components/Common/Loqate-Single-Address-Field/index\";\r\n\r\n// Combination of validations\r\nconst emailValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (validators.email(value)) return validators.email(value);\r\n\r\n return false;\r\n};\r\n\r\nclass NSWReprint extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.onChange = this.onChange.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n this.props.init();\r\n this.props.setEmail();\r\n }\r\n\r\n onAddressSelect = (address) => {\r\n this.props.updateAutocompleteAddress(address);\r\n };\r\n\r\n onSuggestNoResults(userInput) {\r\n if (!userInput || userInput === \"\") return;\r\n }\r\n\r\n onChange(value) {\r\n if (!value) {\r\n this.props.clearAddress();\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n onInputChange,\r\n onCreditCardChange,\r\n onFieldError,\r\n onSubmit,\r\n isSubmitting,\r\n isSubmitted,\r\n showConfirmPopup,\r\n toggleShowConfirmPopup,\r\n clearAddress,\r\n toggleManualAddressEntry,\r\n } = this.props;\r\n const { fullAddress } = this.props.addressEntry;\r\n const {\r\n email,\r\n cardName,\r\n cardNumber,\r\n cardExpiryDate,\r\n cardCvc,\r\n } = this.props.fields;\r\n const { courseCost } = this.props.nswCertificate;\r\n const form = formHandler();\r\n\r\n return (\r\n <>\r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default NSWReprint;\r\n","/**\r\n * Course Enrolment Step 1 Container\r\n * Adam Luck @solvable Jun 10, 2019\r\n */\r\nimport { connect } from \"react-redux\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport nswForm from \"./nsw-reprint-page\";\r\nimport { selectNSWReprint } from \"./redux/reducers\";\r\nimport * as sysActionCreators from \"../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = (state) => {\r\n const stateData = selectNSWReprint(state);\r\n\r\n return {\r\n addressEntry: stateData.addressEntry,\r\n fields: stateData.fields,\r\n fieldErrors: stateData.fieldErrors,\r\n isCreditCardValid: stateData.isCreditCardValid,\r\n isSubmitting: stateData.isSubmitting,\r\n isSubmitted: stateData.isSubmitted,\r\n nswCertificate: stateData.nswCertificate,\r\n showConfirmPopup: stateData.showConfirmPopup,\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n clearAddress: () => {\r\n dispatch(actionCreators.clearAddress());\r\n },\r\n updateAutocompleteAddress: (address) => {\r\n dispatch(actionCreators.updateAutocompleteAddress(address));\r\n },\r\n toggleManualAddressEntry: () => {\r\n dispatch(actionCreators.toggleManualAddressEntry());\r\n },\r\n togglePromoCodeEntry: () => {\r\n dispatch(actionCreators.togglePromoCodeEntry());\r\n },\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onCreditCardChange: (values) => {\r\n dispatch(actionCreators.onCreditCardInputChange(values));\r\n },\r\n setEmail: () => {\r\n dispatch(actionCreators.setEmail());\r\n },\r\n init: () => {\r\n dispatch(actionCreators.init());\r\n },\r\n toggleShowConfirmPopup: () => {\r\n dispatch(actionCreators.toggleShowConfirmPopup());\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n match: ownProps.match,\r\n});\r\n\r\nconst validate = (stateProps) => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter((k) => fieldErrors[k]);\r\n\r\n if (!fields.email) return true;\r\n if (!fields.postcode) return true;\r\n if (!fields.state) return true;\r\n if (!fields.city) return true;\r\n if (!fields.cardName) return true;\r\n if (!stateProps.isCreditCardValid) return true;\r\n if (!fields.streetName) return true;\r\n if (stateProps.addressEntry.enterAddressManually && !fields.streetNumber)\r\n return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n toggleManualAddressEntry: () => {\r\n dispatchProps.dispatch(dispatchProps.toggleManualAddressEntry);\r\n validate(stateProps);\r\n },\r\n onSubmit: () => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmit(\r\n stateProps,\r\n stateProps.fields,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n },\r\n});\r\n\r\nconst nswFormContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(nswForm);\r\n\r\nexport default nswFormContainer;\r\n","import React, { Component } from \"react\";\r\nimport TTGDataTable from \"../../../components/solvable-datatable/solvable-datatable\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\n\r\nclass DataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.columns = this.setupDataTable();\r\n this.state = {\r\n settings: {},\r\n };\r\n this.actionButtonHandler = this.actionButtonHandler.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n this.props.onLoad();\r\n }\r\n\r\n setupDataTable = () => {\r\n return [\r\n {\r\n Header: \"Invoice Number\",\r\n accessor: \"invoiceNumber\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Invoice Date\",\r\n accessor: \"invoiceDate\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Vouchers\",\r\n accessor: \"vouchers\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Total\",\r\n accessor: \"total\",\r\n searchable: true,\r\n },\r\n ];\r\n };\r\n\r\n onSettingsChanged = (settings) => {\r\n this.setState({ settings });\r\n };\r\n\r\n actionButtonHandler = (evt) => {\r\n this.props.downloadTaxInvoice(evt.data.invoiceGuid);\r\n };\r\n\r\n render() {\r\n const { isProcessing } = this.props;\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default DataTable;\r\n","import HttpClient from \"../../../coreLib//http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getTaxInvoices = id => {\r\n return httpClient.get(`v1/corporate/tax-invoices/${id}`);\r\n };\r\n\r\n return {\r\n getTaxInvoices\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport HttpService from \"./service\";\r\nimport YourCoursesService from \"../../../views/Start/redux/service\";\r\nimport IdentityService from \"../../../coreLib/auth/userIdentity\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nexport const onLoad = () => dispatch => {\r\n let httpService = HttpService();\r\n let identity = IdentityService();\r\n let userId = identity.getUserId();\r\n\r\n dispatch(init());\r\n dispatch(onLoadRequest());\r\n httpService\r\n .getTaxInvoices(userId)\r\n .then(resp => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(err => {\r\n dispatch(onLoadFailure());\r\n dispatch(\r\n addNotification(\"There was an error loading the data.\", \"warning\")\r\n );\r\n });\r\n};\r\n\r\nconst init = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_ON_INIT\r\n});\r\n\r\nconst onLoadRequest = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_ON_LOAD_REQUEST\r\n});\r\n\r\nconst onLoadSuccess = payload => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_ON_LOAD_SUCCESS,\r\n payload\r\n});\r\n\r\nconst onLoadFailure = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_ON_LOAD_FAILURE\r\n});\r\n\r\nexport const downloadTaxInvoice = invoiceGuid => dispatch => {\r\n let yourCoursesService = YourCoursesService();\r\n dispatch(onDownloadRequest());\r\n yourCoursesService\r\n .downloadTaxInvoice(invoiceGuid)\r\n .then(resp => {\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"taxinvoice.pdf\");\r\n dispatch(onDownloadSuccess());\r\n })\r\n .catch(err => {\r\n dispatch(onDownloadFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an error downloading the tax invoice.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nconst onDownloadRequest = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_DOWNLOAD_REQUEST\r\n});\r\n\r\nconst onDownloadSuccess = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_DOWNLOAD_SUCCESS\r\n});\r\n\r\nconst onDownloadFailure = () => ({\r\n type: ActionTypes.CORPORATE_TAX_INVOICE_DOWNLOAD_FAILURE\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport DataTable from \"./datatable\";\r\nimport { onLoad, downloadTaxInvoice } from \"../redux/action-creators\";\r\nimport { selectCorporateTaxInvoice } from \"../redux/reducers\";\r\n\r\nconst mapStateToProps = state => {\r\n const stateData = selectCorporateTaxInvoice(state);\r\n return {\r\n data: stateData.data,\r\n isProcessing: stateData.isProcessing\r\n };\r\n};\r\n\r\nconst DataTableContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n { onLoad, downloadTaxInvoice }\r\n )(DataTable)\r\n);\r\n\r\nexport default DataTableContainer;\r\n","import CorporateTaxInvoice from \"./corporate-tax-invoice\";\r\nexport default CorporateTaxInvoice;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport DataTable from \"./datatable/datatable.container\";\r\n\r\nclass CorporateTaxInvoice extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n return (\r\n <>\r\n \r\n \r\n Business Tax Invoices \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default CorporateTaxInvoice;\r\n","/**\r\n * Solvable Collapsible Panel\r\n * - extensible and robust collapsible panel :-)\r\n * - functional component and react hooks\r\n * Props:\r\n * - openByDefault = {true/false} = Initial state of the component if collapsible is open or close.\r\n * - sectionOpen = name of section to open by default\r\n *\r\n * API/Helpers\r\n * - handleInit, collapseState, handleToggle, setToggle, setToggleAll, setBatchToggle, setBatchToggleByState\r\n *\r\n * Note: Collapsible panel fire twice below are the following reasons:\r\n * 1. Initial load, registering its collapsible items id to local state\r\n * 2. Applying setCollapse initial settings which updates the local state and triggers render mechanism.\r\n *\r\n * rcnet @solvable 2019\r\n */\r\nimport React, { useState, useEffect } from \"react\";\r\nimport \"./collapsible-panel.scss\";\r\nimport { ScrollingProvider } from \"react-scroll-section\";\r\n\r\nconst CollapsiblePanel = ({ children, openByDefault, sectionOpen }) => {\r\n const [collapseState, setCollapse] = useState({});\r\n const [idsRegistered, setIdsRegistered] = useState([]);\r\n let _ids = [];\r\n\r\n useEffect(() => {\r\n if (idsRegistered.length === 0) return;\r\n let objState = {};\r\n idsRegistered.forEach((o) => {\r\n if (o !== sectionOpen) {\r\n objState[o] = openByDefault ? openByDefault : false;\r\n } else {\r\n objState[o] = true;\r\n }\r\n });\r\n setCollapse(objState);\r\n }, [openByDefault, sectionOpen, idsRegistered]);\r\n\r\n const handleInit = (id) => {\r\n if (collapseState[id] === undefined) {\r\n _ids.push(id);\r\n setIdsRegistered(_ids);\r\n }\r\n };\r\n\r\n const handleToggle = (id, scrollFn) => {\r\n setCollapse({ ...collapseState, [id]: !collapseState[id] });\r\n };\r\n\r\n const setToggle = (id, isOpen) => {\r\n setCollapse({ ...collapseState, [id]: isOpen });\r\n };\r\n\r\n const setBatchToggle = (ids, isOpen) => {\r\n let clonedState = { ...collapseState };\r\n\r\n ids.forEach((id) => {\r\n clonedState[id] = isOpen;\r\n });\r\n\r\n setCollapse(clonedState);\r\n };\r\n\r\n const setBatchToggleByState = (idsToOpen, idsToClose) => {\r\n let clonedState = { ...collapseState };\r\n\r\n // Ids to Open\r\n idsToOpen.forEach((id) => {\r\n clonedState[id] = true;\r\n });\r\n\r\n idsToClose.forEach((id) => {\r\n clonedState[id] = false;\r\n });\r\n\r\n setCollapse(clonedState);\r\n };\r\n\r\n const setToggleAll = (isOpen) => {\r\n Object.keys(collapseState).forEach((k) => {\r\n collapseState[k] = isOpen;\r\n });\r\n setCollapse({ ...collapseState });\r\n };\r\n\r\n return (\r\n \r\n \r\n {children({\r\n handleInit,\r\n collapseState,\r\n caption: \"Collapsible Panel\",\r\n idsRegistered,\r\n handleToggle,\r\n setToggle,\r\n setToggleAll,\r\n setBatchToggle,\r\n setBatchToggleByState,\r\n })}\r\n
\r\n \r\n );\r\n};\r\n\r\nexport default React.memo(CollapsiblePanel);\r\n","import React from \"react\";\r\n\r\nconst CardHeader2 = ({ title, icon, expandItem }) => {\r\n return (\r\n \r\n \r\n
\r\n \r\n
\r\n
{title}
\r\n
\r\n \r\n );\r\n};\r\n\r\nconst Header = ({ title, icon, expandItem, onClick }) => {\r\n return (\r\n \r\n \r\n
\r\n );\r\n};\r\n\r\nexport default React.memo(Header);\r\n","import React from \"react\";\r\nimport { CardBody } from \"reactstrap\";\r\n\r\nconst Content = ({ component }) => {\r\n return {component} ;\r\n};\r\n\r\nexport default React.memo(Content);\r\n","import React, { useEffect, useState } from \"react\";\r\nimport { Collapse, Card, CardHeader, CardBody } from \"reactstrap\";\r\nimport Header from \"./header\";\r\nimport Content from \"./content\";\r\nimport { Section, SectionLink } from \"react-scroll-section\";\r\nimport { PropTypes } from \"prop-types\";\r\n\r\nconst CollapsibleItem = ({\r\n id,\r\n title,\r\n icon,\r\n children,\r\n init,\r\n collapseState,\r\n toggle,\r\n}) => {\r\n const [toggleFlag, setToggleFlag] = useState(false);\r\n\r\n useEffect(() => {\r\n init(id);\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (Object.keys(collapseState).length === 0) return;\r\n setToggleFlag(collapseState[id]);\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [collapseState]);\r\n\r\n return (\r\n \r\n \r\n \r\n {({ onClick }) => (\r\n <>\r\n \r\n toggle(id, onClick)}\r\n />\r\n \r\n \r\n \r\n \r\n >\r\n )}\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nCollapsibleItem.propTypes = {\r\n icon: PropTypes.string,\r\n};\r\n\r\nCollapsibleItem.defaultProps = {\r\n icon: \"\",\r\n};\r\n\r\nexport default React.memo(CollapsibleItem);\r\n","import React from \"react\";\r\nimport PropTypes from \"prop-types\";\r\nimport CollapsiblePanel from \"../collapsible-panel/collapsible-panel\";\r\nimport CollapsibleItem from \"../collapsible-panel/collapsible-item\";\r\n\r\nconst ContentCollapsiblePanel = ({\r\n sections,\r\n marginTop,\r\n marginBottom,\r\n openSection,\r\n}) => {\r\n return (\r\n \r\n
\r\n {({ handleInit, collapseState, handleToggle }) => {\r\n return sections.map((section, i) => (\r\n \r\n \r\n {section.content}\r\n \r\n
\r\n ));\r\n }}\r\n \r\n
\r\n );\r\n};\r\n\r\nContentCollapsiblePanel.propTypes = {\r\n sections: PropTypes.array.isRequired,\r\n marginTop: PropTypes.number.isRequired,\r\n marginBottom: PropTypes.number.isRequired,\r\n openSection: PropTypes.number.isRequired,\r\n};\r\n\r\nContentCollapsiblePanel.defaultProps = {\r\n sections: [],\r\n marginTop: 3,\r\n marginBottom: 3,\r\n openSection: 0,\r\n};\r\n\r\nexport default ContentCollapsiblePanel;\r\n","import React from \"react\";\r\n\r\nexport const general = [\r\n {\r\n title: \"Are these courses Standard 3.2.2A Compliant?\",\r\n content: (\r\n <>\r\n They sure are! All our courses are current and fully compliant with the\r\n new legislation standard 3.2.2A.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Are these courses Nationally Recognised?\",\r\n content: (\r\n <>\r\n They sure are! We are a Nationally Recognised Training Organisation and\r\n all of the courses that Train to Gain Pty Ltd T/A Food Safety Education\r\n offer are Nationally accredited and recognised. We only offer the most\r\n current and up-to-date course codes.{\" \"}\r\n \r\n Click here to see our Accreditation to provide Food Safety training!\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"What is a Recognised Training Organisation (RTO)?\",\r\n content: (\r\n <>\r\n RTO’s deliver and assess nationally recognised training, and issue\r\n nationally recognised qualifications and statements of attainment.\r\n \r\n \r\n That’s us! Nationally Recognised Training is delivered in\r\n association with Train to Gain Pty Ltd T/A Food Safety Education. (RTO\r\n provider # 22361). Look out for this symbol on our home page to support\r\n our authenticity.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How long do I have to complete my course?\",\r\n content: (\r\n <>\r\n The length of each course will vary on the individual, depending on your\r\n prior knowledge and how you learn. In general, it takes approximately\r\n 2-3 hours to complete each of the Level 1 Food Safety courses and on\r\n average, about 3-4 hours to complete the Food Safety Supervisor courses.\r\n If you want a break, your course will be exactly where you left off when\r\n you come back to it. No repeating anything! If you are looking to fast\r\n track your learning, it is not uncommon for people to sign up and\r\n complete their course in the same day. We allow your enrolment to be\r\n open for 12 months in case life gets in the way!!\r\n >\r\n ),\r\n },\r\n {\r\n title: \"When do I pay for the course?\",\r\n content: (\r\n <>Payment for all our courses are paid after you select your course.>\r\n ),\r\n },\r\n {\r\n title: \"Are there additional costs involved?\",\r\n content: (\r\n <>\r\n No! Payment is made up front with no additional charges. The prices\r\n quoted on our homepage are all inclusive of GST with no hidden fees.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Which payment gateway do you use? Is it secure?\",\r\n content: (\r\n <>\r\n We use eWay as our payment gateway facility that links up to the CBA. We\r\n do not store your credit card numbers.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I don’t have a credit card. How else can I make payment?\",\r\n content: (\r\n <>\r\n If you do not have a credit card, you cannot pay. You could ask your\r\n employer to buy a prepaid voucher or your employer pays with the\r\n business credit card and you reimburse them.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What do I need to have to do your courses online?\",\r\n content: (\r\n <>\r\n \r\n Good understanding of written English \r\n Be able to operate a computer \r\n Have access to the internet \r\n Have access to an email account \r\n Have access to a printer \r\n \r\n Have an observer with Food Safety knowledge and practical skills who\r\n has seen you deal with food in a safe manner\r\n \r\n \r\n A Unique Student Identifier (USI). This is a requirement of the\r\n government for every student doing any nationally recognised\r\n training.\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Do I have to complete my course in one sitting?\",\r\n content: (\r\n <>\r\n No! Take your time and complete the course at your own pace. You can\r\n start, stop and resume your course at time intervals that are suitable\r\n to you. The system will remember your progress. Each time you log into\r\n the website you will be able to resume your course where you last left\r\n it. We understand that most people lead busy lives and have other\r\n important commitments so our online training method allows you to study\r\n in and around other commitments or work rosters.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What if I get a question wrong, what happens then?\",\r\n content: (\r\n <>\r\n If you get any questions wrong then you just repeat the question until\r\n you get it right. You have as many times as you need to get the question\r\n right and you can always contact us for support. You also have the\r\n workbook available on line to assist you in your training.\r\n \r\n \r\n Other training providers may lock you out for days if you get a question\r\n wrong, or make you pay for the whole course again!\r\n \r\n \r\n We will NEVER do that because we understand that everyone learns\r\n differently, therefore, you will not be judged on how long it takes to\r\n learn new information.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What if I have problems with reading and writing?\",\r\n content: (\r\n <>\r\n Train to Gain Pty Ltd T/A Food Safety Education T/A Food Safety\r\n Education provides support for participants who require assistance with\r\n Language Literacy and/or Numeracy (LLN). To assist in identifying any\r\n special learning needs, you are required to provide Train to Gain Pty\r\n Ltd T/A Food Safety Education Pty Ltd T/A Food Safety Education with\r\n information regarding your LLN requirements on your enrolment form,\r\n prior to the start of the training course. Conversely, if you do have\r\n any learning difficulties you are encouraged to discuss these with our\r\n student support team prior to course commencement or during the course\r\n enrolment.\r\n \r\n \r\n Be assured that discussions with our staff will be treated as\r\n confidential.\r\n \r\n \r\n Simply contact us for assistance. You are still able to complete the\r\n course online, but we will talk through how we can assist and support\r\n you in the successful completion of your chosen course.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How will my name appear on my certificate?\",\r\n content: (\r\n <>\r\n Our system will print your name EXACTLY as you enter it into the\r\n enrolment screen. Please take care to spell your name correctly and use\r\n capitals correctly.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I log into my account?\",\r\n content: (\r\n <>\r\n Go to{\" \"}\r\n \r\n https://www.foodsafetyeducation.com.au/Login/\r\n {\" \"}\r\n Click on ‘Login’ at the top right of the screen. Enter your\r\n email address and password you set up when you enrolled in the course.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I can’t remember my password. What do I do?\",\r\n content: (\r\n <>\r\n Enter your email address in the login bar at the top right of the\r\n website. Then click on the ‘forgot password’ tab. This will\r\n give you the option to create a new password.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I’m having trouble logging in. Why?\",\r\n content: (\r\n <>\r\n Have you forgotten your password? Are you entering it incorrectly? Does\r\n your username or password contain a mixture of upper and lower-case\r\n letters? It should be entered exactly as you registered. Are cookies\r\n enabled on your browser? Try logging out of your computer and re-try. If\r\n you can’t determine the reason, please contact us and we will fix\r\n it for you asap. Remember you receive a welcome email when you first\r\n register with us and this email contains your username and password.\r\n Please search your email inbox for your registration email.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Do Food Safety certificates expire?\",\r\n content: (\r\n <>\r\n As per Standard 3.2.2A, Food Handlers and Supervisors must renew their\r\n training every five (5) years. The Statement of Attainment that you\r\n receive doesn’t have an expiry date.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What is a Statement of Attainment?\",\r\n content: (\r\n <>\r\n A Statement of Attainment forms part of an accreditation. We offer units\r\n of competency from the hospitality, retail and health support training\r\n packages. We refer to \"certificates\" in our marketing purely because\r\n this is how the \"Food Safety Certificate\" or the \"Food Safety Supervisor\r\n Certificate\" qualification is perceived in the community and by State\r\n regulators. The Statements of Attainments that you receive from Train to\r\n Gain Pty Ltd T/A Food Safety Education are nationally accredited units\r\n of competency.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I work in Hospitality / Retail, which course is right for me?\",\r\n content: (\r\n <>\r\n It depends on what role you have at work. Different job roles require\r\n different Statements of Attainments.\r\n \r\n \r\n When it comes to the Hospitality & Retail industry a unit of\r\n competency is transferable to the Retail sector and vice versa to the\r\n Hospitality sector in the Food Safety area. However, when it comes to\r\n the Health Food Safety units these are only accepted in those fields. We\r\n always strongly suggest you talk to your local council about what\r\n requirements they need from you as they have their own local policies\r\n regarding Food Safety Accreditation.\r\n \r\n \r\n Statement of Attainments that we offer for Hospitality and Retail:\r\n \r\n \r\n Food Handling Level 1 \r\n \r\n \r\n SITXFSA005 Use Hygienic Practices for Food Safety\r\n \r\n \r\n This unit is for people working in a kitchen, café, restaurant, school\r\n canteen, hotel, supermarkets or other food retail outlets, under\r\n supervision. (Also known as Food Handling Level 1, Food Handlers, RSF,\r\n Food Hygiene Training, Safe Food Handling).\r\n \r\n \r\n Food Handling Level 2 \r\n \r\n \r\n SITXFSA006 Participate in Safe Food Handling Practices\r\n \r\n \r\n This unit is for people who will be the Food Safety Supervisor and who\r\n have already completed Food Handling Level 1.\r\n \r\n \r\n \r\n Food Handling Level 1 & 2 together is the Food Safety Supervisor\r\n Certificate for Hospitality & Retail\r\n \r\n \r\n \r\n SITXFSA005 Use Hygienic Practices for Food Safety & SITXFSA006\r\n Participate in Safe Food Handling Practices\r\n \r\n \r\n This certificate is Level 1 & Level 2 combined into one course. This\r\n is for people who will be the Food Safety Supervisor.\r\n \r\n \r\n If you are unsure about what level of training you need, or the code you\r\n require on your certificate, please contact the Environmental Health\r\n Office at your local council and they will advise you of the correct\r\n training.\r\n \r\n \r\n We understand how confusing it can be to get the certificates you need,\r\n so let us help you get the Food Safety certificate that your council\r\n wants to see!\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"I work in the Health Care/Child Care/Aged Care sector. Which course is right for me?\",\r\n content: (\r\n <>\r\n We offer three units in the one course, as shown below. Combined, they\r\n make up the Food Safety Supervisor Certificate within the Health sector.\r\n We strongly suggest you talk with your local council about what\r\n requirements they need from you as they have their own local policies\r\n regarding Food Safety Accreditation. We also offer level 1 as a\r\n stand-alone unit - Follow Basic Food Safety Practices. This unit is best\r\n for people starting out in the Health industry.\r\n \r\n \r\n Food Handling Level 1 \r\n \r\n \r\n HLTFSE001 Follow Basic Food Safety Practices\r\n \r\n \r\n This course is designed for all people handling food in the Community\r\n and Health Service industries. (Child care, aged care, hospitals, meals\r\n on wheels etc). This unit of competency describes the skills and\r\n knowledge required for basic Food Safety practices including personal\r\n hygiene and conduct when working in a food service environment. It\r\n describes the most basic level of competence required by any person in\r\n the Health industry who directly handles food.\r\n \r\n \r\n \r\n Food Safety Supervisor Certificate for Health & Community\r\n \r\n \r\n \r\n HLTFSE001 Follow Basic Food Safety Practices\r\n \r\n \r\n HLTFSE005 Apply and Monitor Food Safety Requirements\r\n \r\n \r\n HLTFSE007 Oversee the Day to Day Implementation of Food Safety in the\r\n Workplace\r\n \r\n \r\n This is for people who will be the Food Safety Supervisor. There are 3\r\n units of competency altogether.\r\n \r\n \r\n If you are unsure about what level of training you need, or the code you\r\n require on your certificate, please contact the Environmental Health\r\n Office at your local council and they will advise you of the correct\r\n training.\r\n \r\n \r\n We understand how confusing it can be to get the certificates you need,\r\n so let us help you get the Food Safety certificate that your council\r\n wants to see!\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I get my certificate?\",\r\n content: (\r\n <>\r\n \r\n Register your details \r\n \r\n Choose the course you would like to do and make your secure payment\r\n \r\n Complete your enrolment and start your online training \r\n Third-party checklist and assessment is submitted online \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"When do I get my certificate?\",\r\n content: (\r\n <>\r\n When you have successfully completed your online training assessment,\r\n your Statement of Attainment will be issued when your online third-party\r\n form has been successfully submitted. We will send you a\r\n ‘Congratulations’ email with your Statement of Attainment\r\n attached so you can download it, save it and/or print your own copy. You\r\n can also log into the website at any time and download it yourself.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I order course vouchers for my staff?\",\r\n content: (\r\n <>\r\n At Food Safety Education, we offer you the flexibility to purchase Food\r\n Safety Training for your staff so they can proceed with their Food\r\n Safety Training today! Simply click on the “Business” tab in\r\n the navigation bar of this website to gain further information.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I have lost my certificate, what should I do?\",\r\n content: (\r\n <>\r\n If you forgot to save it to your computer and have lost your\r\n certificate, don’t worry!! You can log back in to your student\r\n portal where you will see an option to print your Statement of\r\n Attainment. If you have trouble accessing that option, we will send you\r\n a FREE copy via email. Just let us know and we will email you a copy.\r\n (NSW residents please look under the NSW section of the FAQs about\r\n reprints for NSW).\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Why do I need to enter my date of birth during enrolment?\",\r\n content: (\r\n <>\r\n We are required to verify your identify. It is a government requirement\r\n that we capture this information.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What computer/technical software do I need?\",\r\n content: (\r\n <>\r\n Any modern desktop/PC, tablet or mobile web browser with JavaScript\r\n enabled, a reliable internet connection and a printer so you can print\r\n out your certificate.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Train to Gain Pty Ltd T/A Food Safety Education Refund Policy\",\r\n content: (\r\n <>\r\n SCOPE:\r\n \r\n \r\n 1. This policy covers all fees payable for training services provided\r\n within Train to Gain Pty Ltd T/A Food Safety Education’s scope of\r\n registration. Standards for Registered Training Organisations\r\n (RTO’s) 2015, standard 5.3.\r\n \r\n \r\n PURPOSE:\r\n \r\n \r\n 2. To provide for appropriate handling of clients’ payments and to\r\n facilitate refunds in the case of cancellation by either party. The\r\n refunds process will allow customers the option to disengage from\r\n training in a manner in which a negative impact may be negated or\r\n reduced, depending upon notification time frame and the reasoning for\r\n the refund request.\r\n \r\n \r\n General Rules:\r\n \r\n \r\n 3. The following reflects Train to Gain Pty Ltd T/A Food Safety\r\n Educations refund process for students completing online training with\r\n Train to Gain Pty Ltd T/A Food Safety Education.\r\n \r\n \r\n \r\n \r\n Refunds must be requested in writing to the Director of Train to\r\n Gain via email at contact@traintogain.com.au.\r\n \r\n \r\n Once payment has been made the Director shall determine the outcome\r\n of any refund requests.\r\n \r\n \r\n The Director of Train to Gain Pty Ltd T/A Food Safety Education will\r\n process refund requests within 30 days from the day of receipt.\r\n \r\n \r\n If the online course does not work for the student all efforts will\r\n be made by the Train to Gain Pty Ltd T/A Food Safety Education staff\r\n to assist the student in completing their work.\r\n \r\n \r\n If the online course does not work due to the student’s\r\n computer not supporting their requirements or the student not having\r\n the necessary experience as stipulated by Train to Gain Pty Ltd T/A\r\n Food Safety Education, a refund will not be applicable.\r\n \r\n \r\n If a student changes their mind or sources an alternate course\r\n elsewhere a refund will not be applicable.\r\n \r\n \r\n In some cases, a student may enrol for a wrong course. In this case\r\n we will refund the student only AFTER they have paid and enrolled in\r\n their correct course.\r\n \r\n \r\n If a refund has been granted an administration fee of{\" \"}\r\n $25.00 will incur .\r\n \r\n \r\n Under certain circumstances a course may be transferred to another\r\n party. If all parties agree to the transfer this request must be\r\n made in writing.\r\n \r\n \r\n In the case of a fraudulent fee being paid by a student, Train to\r\n Gain will assist the person making the complaint in every way\r\n possible and will provide personal details about the person to the\r\n Police only. The student or person who claims the fraudulent payment\r\n needs to take the matter up with their financial institution. Train\r\n to Gain accepts no responsibility for fraudulent fees being paid and\r\n will not be liable for refunds to the complainant. The student who\r\n has made the payment under another person’s credit card will\r\n have their enrolment suspended pending all Train to Gain Pty Ltd T/A\r\n Food Safety Education investigations.\r\n \r\n \r\n \r\n \r\n We abide by The Consumer Affairs policies and procedures.\r\n \r\n \r\n Please view the following information about Train to Gain Pty Ltd T/A\r\n Food Safety Education’s rights and obligations regarding refunds\r\n below:\r\n \r\n \r\n \r\n http://www.consumer.vic.gov.au/shopping/refunds-and-returns/change-of-mind\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"Train to Gain Pty Ltd T/A Food Safety Education Privacy Statement and Student Declaration\",\r\n content: (\r\n <>\r\n Privacy Notice\r\n \r\n \r\n Under the Data Provision Requirements 2012, Train to Gain Pty Ltd T/A\r\n Food Safety Education Pty Ltd is required to collect personal\r\n information about you and to disclose that personal information to the\r\n National Centre for Vocational Education Research Ltd (NCVER).\r\n \r\n \r\n Your personal information (including the personal information contained\r\n on this enrolment form and your training activity data) may be used or\r\n disclosed by Train to Gain Pty Ltd T/A Food Safety Education for\r\n statistical, regulatory and research purposes. Train to Gain Pty Ltd T/A\r\n Food Safety Education Pty Ltd may disclose your personal information for\r\n these purposes to third parties, including:\r\n \r\n \r\n \r\n \r\n School – if you are a secondary student undertaking VET, including a\r\n school-based apprenticeship or traineeship;\r\n \r\n \r\n Employer – if you are enrolled in training paid by your employer;\r\n \r\n \r\n Commonwealth and State or Territory government departments and\r\n authorised agencies;\r\n \r\n NCVER; \r\n Organisations conducting student surveys; and \r\n Researchers. \r\n \r\n \r\n \r\n Personal information disclosed to NCVER may be used or disclosed for the\r\n following purposes:\r\n \r\n \r\n \r\n \r\n Issuing statements of attainment or qualification, and populating\r\n authenticated VET transcripts;\r\n \r\n \r\n Facilitating statistics and research relating to education,\r\n including surveys;\r\n \r\n \r\n Understanding how the VET market operates, for policy, workforce\r\n planning and consumer information; and\r\n \r\n \r\n Administering VET, including programme administration, regulation,\r\n monitoring and evaluation.\r\n \r\n \r\n \r\n \r\n You may receive an NCVER student survey which may be administered by an\r\n NCVER employee, agent or third party contractor. You may opt out of the\r\n survey at the time of being contacted. NCVER will collect, hold, use and\r\n disclose your personal information in accordance with the Privacy Act\r\n 1988 (Cth), the VET Data Policy and all NCVER policies and protocols\r\n (including those published on NCVER’s website at{\" \"}\r\n \r\n www.ncver.edu.au\r\n \r\n .\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"Train to Gain Pty Ltd T/A Food Safety Education - Complaints and Appeals Policy\",\r\n content: (\r\n <>\r\n If you have any complaint or issue that you would like to raise with us,\r\n please see our complaints and appeals policy to best direct your enquiry\r\n at the link in our footer of{\" \"}\r\n \r\n www.foodsafetyeducation.com.au\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Accurate Representation of Self\",\r\n content: (\r\n <>\r\n When you register & enrol in a course you agree not to impersonate\r\n or represent any other person than the person on the Enrolment Form. All\r\n course assessments must be completed by the enrolled customer.\r\n \r\n \r\n Your observer will be required to complete a comprehensive Third-Party\r\n Form that states you have been observed dealing with the practical\r\n requirements of the training. Please note – there are random checks done\r\n on the references you provide. Should you be found to be fraudulent in\r\n your information, disciplinary action will be taken. Please see this\r\n information in our student handbook link at the footer of our website at{\" \"}\r\n \r\n www.foodsafetyeducation.com.au\r\n \r\n \r\n \r\n Making false or misleading representation that you are another person or\r\n character is a criminal offence and can give rise to civil liability.\r\n You will also be asked to declare that the work is all yours.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Legal Stuff\",\r\n content: (\r\n <>\r\n Train to Gain Pty Ltd T/A Food Safety Education has a record keeping\r\n system that ensures that student assessment records are collated and\r\n kept for a minimum of four years after the completion of a\r\n students’ course.\r\n \r\n \r\n This is conducted in accordance with the Principles of Assessment\r\n (primarily concerned with the retention, archiving, retrieval and\r\n transfer of records) contained in the Australian Skills Quality\r\n Authority Standards for Registered Training Organisations.\r\n \r\n \r\n \r\n Please click on this link to see our accreditation to do Food Safety\r\n training!\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Legislation\",\r\n content: (\r\n <>\r\n If you would like more information regarding the various State Food\r\n Safety legislation you can access this information at the links below.\r\n \r\n \r\n \r\n Click here to see our Accreditation to provide Food Safety training!\r\n \r\n \r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n \r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n \r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n \r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n \r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n \r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n \r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n \r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n >\r\n ),\r\n },\r\n];\r\n","import React from \"react\";\r\nexport const usi = [\r\n {\r\n title: \"What is a USI number?\",\r\n content: (\r\n <>\r\n When you start your course, you will be asked to supply your Unique\r\n Student Identifier (USI). If you don’t already have a USI\r\n you’ll be asked to create one.\r\n \r\n \r\n The USI is a Government initiative launched on 1st January 2015, making\r\n it compulsory for all students participating in nationally recognised\r\n training to have this unique reference ID. The reference ID is 10\r\n characters long and is comprised of numbers and letters. You can apply\r\n for a USI{\" \"}\r\n \r\n here\r\n \r\n . Once you have a USI, this unique number is assigned to you\r\n permanently.\r\n \r\n \r\n One of the benefits of having this USI is that you can easily access\r\n details of any nationally recognised training that you have completed by\r\n looking it up on the USI website. This means that if you lose your\r\n Statement of Attainment, can’t remember the units that formed your\r\n qualification or don’t know the name of the Registered Training\r\n Organisation (RTO) that issued your qualification it doesn’t\r\n matter, as all of this information is stored in one central location.\r\n \r\n \r\n In the event that we do not have your correct USI number, Train to Gain\r\n Pty Ltd T/A Food Safety Education will have the authority to use your\r\n personal details gained from Train to Gain’s enrolment form. This\r\n information will only be used to enter into the USI registry website to\r\n obtain your correct USI details.\r\n \r\n \r\n \r\n https://www.usi.gov.au/students\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"I don’t have a USI number. How do I get one?\",\r\n content: (\r\n <>\r\n Applying for a Unique Student Identifier (USI) is free of charge and\r\n just takes a few minutes to do. Begin by visiting{\" \"}\r\n \r\n https://www.usi.gov.au/\r\n \r\n \r\n You’ll need to have a form of ID ready to complete your\r\n application. This could be any of the following:\r\n \r\n \r\n \r\n Driver’s Licence \r\n Medicare Card \r\n Australian Passport \r\n Visa \r\n Australian Birth Certificate \r\n Certificate of Registration by Descent \r\n Citizenship Certificate \r\n Immi Card \r\n \r\n \r\n \r\n You’ll then need to supply some personal information including\r\n your name, date of birth, place of birth, gender and country in which\r\n you intend to study. Finally, you need to provide answers to some check\r\n questions that you will be asked the next time you try to access the\r\n website.\r\n \r\n \r\n Once you have completed the online form, you will be issued with a USI\r\n that can be used to access your account and check training details at\r\n any time.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I’m an international student, do I need a USI?\",\r\n content: (\r\n <>\r\n If you are an International student studying in Australia you will need\r\n a USI. All international students in Australia will have been issued\r\n with an Australian Visa. Once you arrive in Australia your visa will be\r\n activated and you will be able to apply for a USI. Please Note:\r\n \r\n \r\n We are not registered for CRICOS. The Commonwealth Register of\r\n Institutions and Courses for Overseas Students is a register of\r\n Australian education institutions that recruit, enrol and teach overseas\r\n students. Please go to this link for further information.{\" \"}\r\n \r\n http://cricos.education.gov.au/\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"I’ve Forgotten my USI\",\r\n content: (\r\n <>\r\n If you have forgotten or lost your USI, you can retrieve it online. You\r\n will need to enter a few details to verify who you are to find your USI.\r\n The details must be the same as those you entered when you applied for a\r\n USI or, if you did so, when you last updated your USI account. Go to{\" \"}\r\n \r\n https://www.usi.gov.au/faqs/i-have-forgotten-my-usi\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Will my USI appear on my training certificate?\",\r\n content: (\r\n <>\r\n No, under legislation your USI must not be printed on your qualification\r\n or statement of attainment.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"I’m not able to proceed with my enrolment but I know my USI is correct\",\r\n content: (\r\n <>\r\n You must make sure that you use the exact same name and format that you\r\n used when applying for your USI. i.e. If you used a middle name when\r\n applying for your USI, you must include your middle name when enrolling\r\n in courses, (all letters are case sensitive). Go here to get more\r\n information about this{\" \"}\r\n \r\n www.usi.gov.au\r\n \r\n >\r\n ),\r\n },\r\n];\r\n","import React from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nexport const thirdParty = [\r\n {\r\n title: \"Why do I need a third-party observer?\",\r\n content: (\r\n <>\r\n Because we offer online training, we need to prove your practical skills\r\n in Food Safety and we do this by an online third-party checklist form\r\n that is emailed to your nominated observer. There are some things we\r\n can’t see you doing through your computer – such as washing your\r\n hands. This is a short form with a checklist.\r\n \r\n \r\n Observer reports are a fundamental part of the assessment process at\r\n Food Safety Education. It’s a mandatory requirement for our\r\n accredited Food Safety courses that students are observed performing\r\n certain tasks.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Who can be my third-party observer?\",\r\n content: (\r\n <>\r\n Your observer checklist can be submitted by anyone who works in the food\r\n industry who has observed you working with food over a period of time.\r\n It could also be someone you work with currently, have worked with in\r\n the past, or someone from a community organisation where you have\r\n volunteered your time. Your observer must have sufficient skills &\r\n knowledge and is in a current supervisory role. Many places are happy to\r\n have volunteers help out in return for observing you do the tasks listed\r\n on the observer report. Your Observer can be:\r\n \r\n \r\n \r\n Past or Present Supervisor/Employer/Manager \r\n Past or Present Volunteer Supervisor/Manager \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"What happens after I nominate my observer?\",\r\n content: (\r\n <>\r\n Once you have entered your observers email into the enrolment form, a\r\n system generated email will be sent to your observer with the\r\n third-party checklist. The third-party checklist needs to be correctly\r\n filled out and then submitted back to us online.\r\n \r\n \r\n It’s important to be in contact with your observer straight away\r\n to let them know that you have nominated them for this task and request\r\n that they return the completed checklist asap.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Here is an example of a Third Party Form\",\r\n content: (\r\n <>\r\n \r\n \r\n \r\n Click here to see an example of the Third Party Form\r\n \r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"What are the assessments?\",\r\n content: (\r\n <>\r\n There are multiple choice questions and open text answers that are\r\n required to be completed to gain competency. Case studies are included\r\n for the NSW courses only.\r\n >\r\n ),\r\n },\r\n];\r\n","import React from \"react\";\r\nexport const nsw = [\r\n {\r\n title: \"I’m in NSW - What certificate do I need?\",\r\n content: (\r\n <>\r\n If you are wanting to work in a food business in NSW it is a requirement\r\n to have a specific NSW Food Safety Supervisor Certificate. We are\r\n approved and registered with the NSW Food Authority – RTO Approval\r\n Number: 25085.\r\n \r\n \r\n Please click on the link below for your assurance.\r\n \r\n \r\n \r\n http://www.foodauthority.nsw.gov.au/rp/fss-food-safety-supervisors/approved-training-providers/all-rtos\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I get my NSW Food Safety Supervisor Certificate?\",\r\n content: (\r\n <>\r\n It’s as easy as following these 4 steps for the\r\n quickest, cheapest and most convenient way to get your NSW Food Safety\r\n Supervisor Certificate:\r\n \r\n \r\n \r\n Register \r\n \r\n Select the NSW $179 NSW Food Safety Supervisor Certificate course\r\n \r\n \r\n Make payment and enter the postal address where your NSW Food Safety\r\n Supervisor Certificate is to be posted to\r\n \r\n \r\n Start enrolment and complete online course. Third-party checklist\r\n and case studies submitted online\r\n \r\n \r\n \r\n \r\n Upon completion of the course you will receive the NSW Food Safety\r\n Supervisor Certificate PLUS a Nationally Accredited Statement of\r\n Attainment that is recognised in every other State of Australia.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How long does it take to do the course?\",\r\n content: (\r\n <>\r\n Depending on your level of understanding and comprehension it can take\r\n anything from three to four hours to complete. Some students have taken\r\n eight or nine hours and some, longer. There is no right answer to this\r\n question but remember, we allow you up to twelve months to complete your\r\n training.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"How long does it take to get the NSW Food Safety Supervisor Certificate (hard copy)?\",\r\n content: (\r\n <>\r\n We express post your NSW Food Safety Supervisor Certificate to your\r\n nominated postal address, within 5-7 business days of you having\r\n completed your online training.\r\n \r\n \r\n You will also receive the Nationally Recognised Statement of Attainment,\r\n which will be emailed to you automatically. This Statement of Attainment\r\n is also acceptable in all the other States of Australia.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"I didn’t get my NSW Food Safety Supervisor Certificate in the mail?\",\r\n content: (\r\n <>\r\n If a certificate has been deemed successfully delivered by Australia\r\n Post (or has been returned due to an incorrect or insufficient address\r\n being supplied) there will be a $45 fee charged for any reissued\r\n certificates. Please email or call our student support team to assist\r\n you further.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"I need a reprint of my NSW Food Safety Supervisor Certificate?\",\r\n content: (\r\n <>\r\n In your student portal you will have the option to purchase a reprint of\r\n your NSW certificate. You must have already completed your NSW\r\n certificate with Train to Gain Pty Ltd T/A Food Safety Education in\r\n order to obtain another certificate. Simply select the option for a\r\n reprint. There is a $45.00 fee. This needs to be paid online using a\r\n credit card at the time of your order. You MUST enter your name as you\r\n had previously registered with us so we can confirm that you have\r\n successfully completed the training. A current postal address is\r\n required. Your new certificate will be posted within 5-7 business days\r\n of payment.\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Do I need a prerequisite for this training?\",\r\n content: (\r\n <>\r\n No! There are no prerequisites for enrolling in our courses, so anyone\r\n can join.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"Will I get a NSW Food Safety Supervisor Certificate if I do the 3 units from the health sector?\",\r\n content: (\r\n <>\r\n NO!! The NSW Food Authority only recognises units from the hospitality\r\n and retail sector.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"Why does the NSW Food Safety Supervisor Certificate course cost more than the other states?\",\r\n content: (\r\n <>\r\n The NSW Food Authority have implemented their own Food Safety Supervisor\r\n Certificate that is required in NSW only.\r\n \r\n \r\n The costs are explained below:\r\n \r\n \r\n Total price for a NSW Food Safety Supervisor Certificate with us is\r\n $179.00. With Train to Gain Pty Ltd T/A Food Safety Education (RTO #\r\n 22361), there are no hidden fees or charges.\r\n \r\n \r\n $139 Nationally Accredited Certificate - This can be\r\n downloaded automatically at the successful completion of your course.\r\n \r\n \r\n $30 NSW Food Safety Supervisor Certificate - This is\r\n what the NSW Food Authority charge us!\r\n \r\n \r\n \r\n $10 to cover Express Postage, Administration & Handling\r\n {\" \"}\r\n - This ensures you will receive your certificate within 5 to 7 business\r\n days via express post after you have successfully completed the course.\r\n >\r\n ),\r\n },\r\n {\r\n title:\r\n \"What do I do when my NSW Food Safety Supervisor certification expires?\",\r\n content: (\r\n <>\r\n The NSW Food Safety Supervisor Certificate needs to be renewed every 5\r\n years. You will need to ensure that the NSW Food Safety Supervisor\r\n Certificate is kept on the premises at all times, as council inspectors\r\n may request to view the certificate during an inspection.\r\n \r\n \r\n Students have up to 90 days to apply for re-certification with an\r\n approved RTO (which is us!) following the expiry of their NSW Food\r\n Safety Supervisor Certificate. Should it be left longer than 90 days,\r\n the entire course must be re-completed to provide for issue of a new NSW\r\n Food Safety Supervisor Certificate.\r\n \r\n \r\n NSW businesses to replace or renew a NSW Food Safety Supervisor\r\n Certificate within 30 days in the event of a NSW Food Safety Supervisor\r\n Certificate holder leaving the business, or upon expiry of the NSW Food\r\n Safety Supervisor Certificate as per NSW legislation.\r\n \r\n \r\n Please click on the link below to gain more information from the NSW\r\n Food Authority website.\r\n \r\n \r\n \r\n http://www.foodauthority.nsw.gov.au/rp/fss-food-safety-supervisors?utm_campaign=redirected\r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I attain my NSW Food Safety Refresher course?\",\r\n content: (\r\n <>\r\n We offer the NSW Food Safety Refresher course for ONLY $149. If you\r\n already have a NSW Food Safety Supervisor Certificate, you can renew it\r\n online with us today! We accept previous certificates from other\r\n registered training providers as long as you have your previous NSW Food\r\n Safety Supervisor Certificate number.\r\n \r\n \r\n Simply:\r\n \r\n \r\n \r\n \r\n Log back in (top right) of the website or re register if you have\r\n updated your details.\r\n \r\n Select the NSW Refresher Course option. \r\n \r\n \r\n Please click on the link below to gain more information from the NSW\r\n Food Authority website.\r\n \r\n \r\n \r\n http://www.foodauthority.nsw.gov.au/rp/fss-food-safety-supervisors?utm_campaign=redirected\r\n \r\n >\r\n ),\r\n },\r\n];\r\n","import React, { useEffect, useState } from \"react\";\r\nimport { useParams } from \"react-router-dom\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\nimport LinkButton from \"components/link-button/link-button\";\r\n\r\nimport { general } from \"constants/faqs-content/faqs-general\";\r\nimport { usi } from \"constants/faqs-content/faqs-usi\";\r\nimport { thirdParty } from \"constants/faqs-content/faqs-third-party\";\r\nimport { nsw } from \"constants/faqs-content/faqs-nsw\";\r\n\r\nimport \"./faqs.scss\";\r\n\r\nconst FAQs = () => {\r\n const { faqPage } = useParams();\r\n\r\n const [faqContent, setFaqContent] = useState(null);\r\n\r\n useEffect(() => {\r\n switch (faqPage) {\r\n case \"usi\":\r\n setFaqContent(usi);\r\n break;\r\n case \"third-party-observer-assessment\":\r\n setFaqContent(thirdParty);\r\n break;\r\n case \"nsw-students\":\r\n setFaqContent(nsw);\r\n break;\r\n default:\r\n setFaqContent(general);\r\n break;\r\n }\r\n }, [faqPage]);\r\n\r\n return (\r\n \r\n \r\n \r\n
Frequently Asked Questions \r\n
\r\n {\" \"}\r\n \r\n \r\n \r\n \r\n
\r\n {faqContent && (\r\n
\r\n )}\r\n
\r\n \r\n );\r\n};\r\n\r\nexport default FAQs;\r\n","/**\r\n * Survey Service\r\n */\r\nimport HttpClient from \"../../coreLib/http/httpClient\";\r\n\r\nconst CourseCompletedService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = courseContentToken => {\r\n let promise1 = httpClient.get(\r\n `/v1/userCourse/${courseContentToken}/status`\r\n );\r\n let promise2 = httpClient.get(\r\n `/v1/userCourse/${courseContentToken}/course`\r\n );\r\n\r\n let promiseDeferred = new Promise((resolve, reject) => {\r\n Promise.all([promise1, promise2])\r\n .then(values => {\r\n const result = {\r\n data: {\r\n status: values[0].data,\r\n courseInfo: values[1].data\r\n }\r\n };\r\n\r\n resolve(result);\r\n })\r\n .catch(err => reject(err));\r\n });\r\n\r\n return promiseDeferred;\r\n };\r\n\r\n return {\r\n getStatus\r\n };\r\n};\r\n\r\nexport default CourseCompletedService;\r\n","export const surveyQuestions = [\r\n {\r\n questionId: 1,\r\n question: \"I developed the skills expected from this training.\"\r\n },\r\n {\r\n questionId: 2,\r\n question: \"I identified ways to build on my current knowledge and skills.\"\r\n },\r\n {\r\n questionId: 3,\r\n question: \"The training focused on relevant skills.\"\r\n },\r\n {\r\n questionId: 4,\r\n question: \"I developed the knowledge expected from this training.\"\r\n },\r\n {\r\n questionId: 5,\r\n question: \"The training prepared me well for work.\"\r\n },\r\n {\r\n questionId: 6,\r\n question: \"I set high standards for myself in this training.\"\r\n },\r\n {\r\n questionId: 7,\r\n question: \"The training had a good mix of theory and practice.\"\r\n },\r\n {\r\n questionId: 8,\r\n question: \"I looked for my own resources to help me learn.\"\r\n },\r\n {\r\n questionId: 9,\r\n question: \"Overall, I am satisfied with the training.\"\r\n },\r\n {\r\n questionId: 10,\r\n question: \"I would recommend the training organisation to others.\"\r\n },\r\n {\r\n questionId: 11,\r\n question: \"Training organisation staff respected my background and needs.\"\r\n },\r\n {\r\n questionId: 12,\r\n question: \"I pushed myself to understand things I found confusing.\"\r\n },\r\n {\r\n questionId: 13,\r\n question: \"Trainers had an excellent knowledge of the subject content.\"\r\n },\r\n {\r\n questionId: 14,\r\n question: \"I received useful feedback on my assessments.\"\r\n },\r\n {\r\n questionId: 15,\r\n question:\r\n \"The way I was assessed was a fair test of my skills and knowledge.\"\r\n },\r\n {\r\n questionId: 16,\r\n question: \"I learned to work with people.\"\r\n },\r\n {\r\n questionId: 17,\r\n question: \"The training was at the right level of difficulty for me.\"\r\n },\r\n {\r\n questionId: 18,\r\n question: \"The amount of work I had to do was reasonable.\"\r\n },\r\n {\r\n questionId: 19,\r\n question: \"Assessments were based on realistic activities.\"\r\n },\r\n {\r\n questionId: 20,\r\n question: \"It was always easy to know the standards expected.\"\r\n },\r\n {\r\n questionId: 21,\r\n question: \"Training facilities and materials were in good condition.\"\r\n },\r\n {\r\n questionId: 22,\r\n question: \"I usually had a clear idea of what was expected of me.\"\r\n },\r\n {\r\n questionId: 23,\r\n question: \"Trainers explained things clearly.\"\r\n },\r\n {\r\n questionId: 24,\r\n question:\r\n \"The training organisation had a range of services to support learners.\"\r\n },\r\n {\r\n questionId: 25,\r\n question: \"I learned to plan and manage my work.\"\r\n },\r\n {\r\n questionId: 26,\r\n question:\r\n \"The training used up-to-date equipment, facilities and materials.\"\r\n },\r\n {\r\n questionId: 27,\r\n question: \"I approached trainers if I needed help.\"\r\n },\r\n {\r\n questionId: 28,\r\n question: \"Trainers made the subject as interesting as possible.\"\r\n },\r\n {\r\n questionId: 29,\r\n question: \"I would recommend the training to others.\"\r\n },\r\n {\r\n questionId: 30,\r\n question:\r\n \"The training organisation gave appropriate recognition of existing knowledge and skills.\"\r\n },\r\n {\r\n questionId: 31,\r\n question: \"Training resources were available when I needed them.\"\r\n },\r\n {\r\n questionId: 32,\r\n question: \"I was given enough material to keep up my interest.\"\r\n },\r\n {\r\n questionId: 33,\r\n question: \"The training was flexible enough to meet my needs.\"\r\n },\r\n {\r\n questionId: 34,\r\n question: \"Trainers encouraged learners to ask questions.\"\r\n },\r\n {\r\n questionId: 35,\r\n question:\r\n \"Trainers made it clear right from the start what they expected from me.\"\r\n }\r\n];\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport CourseCompletedService from \"./../course-completed-service\";\r\nimport { surveyQuestions } from \"./../../../constants/survey-content\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const loadData = (courseContentToken, history) => {\r\n return dispatch => {\r\n dispatch(loadDataRequest());\r\n\r\n const service = CourseCompletedService();\r\n\r\n service\r\n .getStatus(courseContentToken)\r\n .then(resp => {\r\n const { hasCompleted, thirdPartyFormCompleted } = resp.data.status;\r\n const { courseTitle, courseId } = resp.data.courseInfo;\r\n\r\n //if (!hasCompleted || (hasCompleted && thirdPartyFormCompleted)) {\r\n if (!hasCompleted) {\r\n history.push(`/course-content/${courseContentToken}`);\r\n } else {\r\n let payload = {\r\n hasBeenCompleted: hasCompleted,\r\n thirdPartyFormCompleted: thirdPartyFormCompleted,\r\n courseTitle: courseTitle,\r\n courseId: courseId,\r\n courseContentToken: courseContentToken\r\n };\r\n\r\n dispatch(loadDataSuccess(payload));\r\n }\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n dispatch(loadDataFailure(err));\r\n dispatch(\r\n addNotification(\"Unable to load data for this page.\", \"error\")\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst loadDataRequest = () => ({\r\n type: ActionTypes.SURVEY_COURSE_COMPLETED_LOAD_DATA_REQUEST\r\n});\r\n\r\nconst loadDataSuccess = payload => ({\r\n type: ActionTypes.SURVEY_COURSE_COMPLETED_LOAD_DATA_SUCCESS,\r\n payload: {\r\n ...payload\r\n }\r\n});\r\n\r\nconst loadDataFailure = err => ({\r\n type: ActionTypes.SURVEY_COURSE_COMPLETED_LOAD_DATA_FAILURE,\r\n payload: err\r\n});\r\n","import React, { useEffect } from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport { Button } from \"reactstrap\";\r\nimport \"./course-completed.scss\";\r\nimport ContentSection from \"../../components/Content-Section/index\";\r\nimport BlockUiFx from \"./../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\n\r\nconst NswCertificateMessage = (props) => {\r\n const { courseId } = props;\r\n if (parseInt(courseId) === 6)\r\n return (\r\n \r\n Your NSW Food Safety Supervisor Certificate will be posted to you within\r\n 7 business days\r\n
\r\n );\r\n\r\n return null;\r\n};\r\n\r\nconst CourseCompleted = (props) => {\r\n const {\r\n courseTitle,\r\n hasBeenCompleted,\r\n thirdPartyFormCompleted,\r\n courseId,\r\n loadData,\r\n isLoading,\r\n onRedirectToThirdParty,\r\n courseContentToken,\r\n } = props;\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, []);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n {hasBeenCompleted && !thirdPartyFormCompleted && (\r\n <>\r\n
Well done, almost there... \r\n
\r\n We are still waiting for your observer to complete your third\r\n party form.\r\n
\r\n
\r\n Please contact your observer and ask them to complete your third\r\n party form. If they have lost or deleted their email with your\r\n third party form link, you can resend it by clicking the 'View\r\n Third Party Form' button below, then click the 'Email this form\r\n to your Observer' button on your third party form.\r\n
\r\n
\r\n View Third Party Form\r\n \r\n >\r\n )}\r\n {hasBeenCompleted && thirdPartyFormCompleted && (\r\n <>\r\n
Congratulations! \r\n
\r\n You have successfully completed the test for:\r\n
\r\n
{courseTitle} \r\n
\r\n
\r\n Download Certificate\r\n \r\n >\r\n )}\r\n
\r\n \r\n \r\n );\r\n};\r\n\r\nexport default CourseCompleted;\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport CourseCompleted from \"./Course-Completed\";\r\nimport { selectCourseCompleted } from \"./redux/reducer\";\r\n\r\nfunction mapStateToProps(state) {\r\n const stateData = selectCourseCompleted(state);\r\n\r\n return {\r\n hasBeenCompleted: stateData.hasBeenCompleted,\r\n thirdPartyFormCompleted: stateData.thirdPartyFormCompleted,\r\n courseTitle: stateData.courseTitle,\r\n courseId: stateData.courseId,\r\n isLoading: stateData.isLoading\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n courseContentToken: ownProps.match.params.id\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n loadData: () => {\r\n dispatchProps.dispatch(\r\n actionCreators.loadData(\r\n dispatchProps.courseContentToken,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n onRedirectToThirdParty: () => {\r\n dispatchProps.history.push(\r\n `/third-party-form/${dispatchProps.courseContentToken}`\r\n );\r\n }\r\n});\r\n\r\nconst CourseCompletedContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n )(CourseCompleted)\r\n);\r\n\r\nexport default CourseCompletedContainer;\r\n","/**\r\n * Survey Service\r\n */\r\nimport HttpClient from \"./../../coreLib/http/httpClient\";\r\n\r\nconst CourseSurveyService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getCourseId = courseContentToken =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/ids`);\r\n\r\n const getStatus = courseContentToken =>\r\n httpClient.get(`/v1/userCourse/${courseContentToken}/status`);\r\n\r\n const getSurveys = courseContentToken => {\r\n let promise1 = getCourseId(courseContentToken);\r\n let promise2 = getStatus(courseContentToken);\r\n\r\n let promiseDeferred = new Promise((resolve, reject) => {\r\n Promise.all([promise1, promise2])\r\n .then(resp => {\r\n httpClient\r\n .get(`/v1/survey/${resp[0].data.userCourseId}`)\r\n .then(result => {\r\n resolve({\r\n ...result.data,\r\n userCourseId: resp[0].data.userCourseId,\r\n status: resp[1].data\r\n });\r\n })\r\n .catch(e => reject(e));\r\n })\r\n .catch(err => reject(err));\r\n });\r\n\r\n return promiseDeferred;\r\n };\r\n\r\n const createSurvey = data => {\r\n let payload = {\r\n userCourseId: data.userCourseId,\r\n bestAspects: data.bestAspects,\r\n needImprovement: data.needImprovement,\r\n undertakingApprenticeshipOrTraineeship: data.uat === \"1\",\r\n rpl: data.rpl === \"1\",\r\n surveyResponses: data.surveyResponses\r\n };\r\n\r\n return httpClient.post(\"v1/survey\", payload);\r\n };\r\n\r\n const updateSurvey = (surveyId, data) => {\r\n let payload = {\r\n userCourseId: data.userCourseId,\r\n bestAspects: data.bestAspects,\r\n needImprovement: data.needImprovement,\r\n undertakingApprenticeshipOrTraineeship: data.uat === \"1\",\r\n rpl: data.rpl === \"1\",\r\n surveyResponses: data.surveyResponses\r\n };\r\n\r\n return httpClient.put(`v1/survey/${surveyId}`, payload);\r\n };\r\n\r\n return {\r\n getCourseId,\r\n getSurveys,\r\n createSurvey,\r\n updateSurvey\r\n };\r\n};\r\n\r\nexport default CourseSurveyService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\nimport CourseSurveyService from \"./../course-survey-service\";\r\nimport { surveyQuestions } from \"./../../../constants/survey-content\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const loadData = (courseContentToken, history) => {\r\n return dispatch => {\r\n dispatch(loadDataRequest());\r\n\r\n const service = CourseSurveyService();\r\n\r\n service\r\n .getSurveys(courseContentToken)\r\n .then(resp => {\r\n const payload = {\r\n ...resp,\r\n surveyQuestions\r\n };\r\n\r\n if (!payload.status.hasCompleted) {\r\n history.push(`/course-content/${courseContentToken}`);\r\n } else {\r\n dispatch(loadDataSuccess(payload));\r\n }\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n dispatch(loadDataFailure(err));\r\n dispatch(addNotification(\"Unable to load survey.\", \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst loadDataRequest = () => ({\r\n type: ActionTypes.SURVEY_LOAD_DATA_REQUEST\r\n});\r\n\r\nconst loadDataSuccess = payload => ({\r\n type: ActionTypes.SURVEY_LOAD_DATA_SUCCESS,\r\n payload: {\r\n ...payload\r\n }\r\n});\r\n\r\nconst loadDataFailure = err => ({\r\n type: ActionTypes.SURVEY_LOAD_DATA_FAILURE,\r\n payload: err\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.SURVEY_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n\r\n// =======================\r\n// Survey Create\r\n// =======================\r\n\r\nexport const createSurvey = (data, history, courseContentToken) => {\r\n return dispatch => {\r\n dispatch(createSurveyRequest());\r\n\r\n // Build questionnaires\r\n const answeredQuestions = sanitizeAnsweredQuestions(data.fields);\r\n let result = getQuestionsToSubmit(surveyQuestions, answeredQuestions);\r\n let payload = {\r\n userCourseId: data.userCourseId,\r\n bestAspects: data.fields.bestAspects,\r\n needImprovement: data.fields.needImprovement,\r\n undertakingApprenticeshipOrTraineeship: data.fields.uat === \"1\",\r\n rpl: data.fields.rpl === \"1\",\r\n surveyResponses: [...result]\r\n };\r\n\r\n const service = CourseSurveyService();\r\n service\r\n .createSurvey(payload)\r\n .then(resp => {\r\n dispatch(createSurveySuccess());\r\n history.push(`/course-completed/${courseContentToken}`);\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n dispatch(createSurveyFailure(err));\r\n dispatch(addNotification(\"Unable to save survey.\", \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst createSurveyRequest = () => ({\r\n type: ActionTypes.SURVEY_SUBMIT_REQUEST\r\n});\r\n\r\nconst createSurveySuccess = payload => ({\r\n type: ActionTypes.SURVEY_SUBMIT_SUCCESS,\r\n payload: {\r\n ...payload\r\n }\r\n});\r\n\r\nconst createSurveyFailure = err => ({\r\n type: ActionTypes.SURVEY_SUBMIT_FAILURE,\r\n payload: err\r\n});\r\n\r\nconst getQuestionsToSubmit = (questions, answeredQuestions) => {\r\n let result = questions.map(o => {\r\n let qr = answeredQuestions.find(x => x.questionId == o.questionId);\r\n return {\r\n questionId: o.questionId,\r\n response: qr ? qr.response : null\r\n };\r\n });\r\n\r\n return result;\r\n};\r\n\r\nconst sanitizeAnsweredQuestions = answeredQuestions => {\r\n let aq = Object.keys(answeredQuestions)\r\n .filter(k => k.split(\"-\")[0] == \"question\")\r\n .map(k => {\r\n return {\r\n questionId: k.split(\"-\")[1],\r\n response: answeredQuestions[k]\r\n };\r\n });\r\n\r\n return aq;\r\n};\r\n\r\n// =======================\r\n// Survey Update\r\n// =======================\r\n\r\nexport const updateSurvey = (surveyId, data, history, courseContentToken) => {\r\n return dispatch => {\r\n dispatch(updateSurveyRequest());\r\n\r\n // Build questionnaires\r\n const answeredQuestions = sanitizeAnsweredQuestions(data.fields);\r\n let result = getQuestionsToSubmit(surveyQuestions, answeredQuestions);\r\n let payload = {\r\n userCourseId: data.userCourseId,\r\n bestAspects: data.fields.bestAspects,\r\n needImprovement: data.fields.needImprovement,\r\n uat: data.fields.uat,\r\n rpl: data.fields.rpl,\r\n surveyResponses: [...result]\r\n };\r\n\r\n const service = CourseSurveyService();\r\n service\r\n .updateSurvey(surveyId, payload)\r\n .then(resp => {\r\n dispatch(updateSurveySuccess());\r\n history.push(`/course-completed/${courseContentToken}`);\r\n })\r\n .catch(err => {\r\n console.error(err);\r\n dispatch(updateSurveyFailure(err));\r\n dispatch(addNotification(\"Unable to update survey.\", \"error\"));\r\n });\r\n };\r\n};\r\n\r\nconst updateSurveyRequest = () => ({\r\n type: ActionTypes.SURVEY_SUBMIT_REQUEST\r\n});\r\n\r\nconst updateSurveySuccess = payload => ({\r\n type: ActionTypes.SURVEY_SUBMIT_SUCCESS,\r\n payload: {\r\n ...payload\r\n }\r\n});\r\n\r\nconst updateSurveyFailure = err => ({\r\n type: ActionTypes.SURVEY_SUBMIT_FAILURE,\r\n payload: err\r\n});\r\n","import React, { useEffect } from \"react\";\r\nimport PageTitle from \"../../components/Common/Page-Title/Page-Title\";\r\nimport { Table, Input, Form, FormGroup, Label, Button } from \"reactstrap\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport \"./course-survey.scss\";\r\nimport RadioButtonList from \"./../../components/Common/Fields/Radio-Button-List\";\r\nimport InputField from \"./../../components/Common/Fields/Input-Field\";\r\nimport { required } from \"../../components/Common/Fields/Validators/Field-Validators\";\r\nimport BlockUiFx from \"./../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport ButtonFx from \"./../../components/Common/Button-Fx/Button-Fx\";\r\nimport formHandler from \"./../../components/Common/Fields/form-handler\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\n\r\nconst CourseSurvey = (props) => {\r\n const {\r\n aatItems,\r\n rplItems,\r\n surveyQuestions,\r\n isLoading,\r\n onSubmit,\r\n onFieldError,\r\n onInputChange,\r\n loadData,\r\n validate,\r\n fields,\r\n match,\r\n } = props;\r\n\r\n const form = formHandler();\r\n\r\n useEffect(() => {\r\n let userCourseToken = match.params.id;\r\n loadData(userCourseToken);\r\n }, []);\r\n\r\n const RenderQuestionnaires = (props) => {\r\n const isChecked = (id, compareTo) => {\r\n let result =\r\n props.fields[id] != null && props.fields[id] === compareTo\r\n ? true\r\n : false;\r\n return result;\r\n };\r\n\r\n const questions = props.src.map((o, i) => (\r\n \r\n {o.question} \r\n \r\n {/* Strongly Agree */}\r\n \r\n props.onInputChange({\r\n name: e.target.name,\r\n value: parseInt(e.target.value),\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n Strongly Agree\r\n \r\n \r\n \r\n {/* Agree */}\r\n \r\n props.onInputChange({\r\n name: e.target.name,\r\n value: parseInt(e.target.value),\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n Agree\r\n \r\n \r\n \r\n {/* Disagree */}\r\n \r\n props.onInputChange({\r\n name: e.target.name,\r\n value: parseInt(e.target.value),\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n Disagree\r\n \r\n \r\n \r\n {/* Strongly Disagree */}\r\n \r\n props.onInputChange({\r\n name: e.target.name,\r\n value: parseInt(e.target.value),\r\n error: false,\r\n })\r\n }\r\n />\r\n \r\n Strongly Disagree\r\n \r\n \r\n \r\n ));\r\n return questions;\r\n };\r\n\r\n return (\r\n \r\n \r\n {!isLoading ? (\r\n \r\n
\r\n \r\n
Survey \r\n
\r\n Thanks! We really appreciate you filling in this form as much as\r\n you can, it helps us improve our service to you.\r\n
\r\n
\r\n
\r\n \r\n
\r\n ) : null}\r\n \r\n );\r\n};\r\n\r\nexport default CourseSurvey;\r\n","import { connect } from \"react-redux\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport CourseSurvey from \"./Course-Survey\";\r\nimport { addNotification } from \"../../redux/system/system-action-creators\";\r\nimport { selectSurvey } from \"./redux/reducer\";\r\n\r\nfunction mapStateToProps(state) {\r\n const surveyStateData = selectSurvey(state);\r\n\r\n return {\r\n userCourseId: surveyStateData.userCourseId,\r\n surveyId: surveyStateData.surveyId,\r\n surveyQuestions: surveyStateData.surveyQuestions,\r\n aatItems: surveyStateData.yesNoLookups,\r\n rplItems: surveyStateData.yesNoLookups,\r\n fields: surveyStateData.fields,\r\n fieldErrors: surveyStateData.fieldErrors,\r\n\r\n isLoading: surveyStateData.isLoading\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onFieldError: error => dispatch(addNotification(error, \"Error\")),\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n match: ownProps.match\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n loadData: courseContentToken => {\r\n dispatchProps.dispatch(\r\n actionCreators.loadData(courseContentToken, dispatchProps.history)\r\n );\r\n },\r\n onSubmit: () => {\r\n if (validate(stateProps)) return;\r\n\r\n if (!stateProps.surveyId) {\r\n const createPayload = {\r\n userCourseId: stateProps.userCourseId,\r\n fields: stateProps.fields\r\n };\r\n\r\n dispatchProps.dispatch(\r\n actionCreators.createSurvey(\r\n createPayload,\r\n dispatchProps.history,\r\n dispatchProps.match.params.id\r\n )\r\n );\r\n } else {\r\n const updatePayload = {\r\n userCourseId: stateProps.userCourseId,\r\n fields: stateProps.fields\r\n };\r\n\r\n dispatchProps.dispatch(\r\n actionCreators.updateSurvey(\r\n stateProps.surveyId,\r\n updatePayload,\r\n dispatchProps.history,\r\n dispatchProps.match.params.id\r\n )\r\n );\r\n }\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n }\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n\r\n if (!fields.bestAspects) return true;\r\n if (!fields.needImprovement) return true;\r\n if (!fields.uat || fields.uat === \"-1\") return true;\r\n if (!fields.rpl || fields.rpl === \"-1\") return true;\r\n\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst CourseSurveyContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(CourseSurvey);\r\n\r\nexport default CourseSurveyContainer;\r\n","import HttpClient from \"coreLib/http/httpClient\";\r\nimport CryptoJS from \"crypto-js\";\r\nimport Config from \"config\";\r\n\r\nconst ApiService = () => {\r\n const httpClient = HttpClient();\r\n\r\n const getCourseContentGuide = async (courseContentToken) => {\r\n return await httpClient\r\n .get(`/v1/usercourse/${courseContentToken}/content-guides`)\r\n .then((resp) => {\r\n var data = decryptPayload(\r\n resp.data,\r\n Config.crypto_key,\r\n Config.crypto_vector\r\n );\r\n return data;\r\n });\r\n };\r\n\r\n const decryptPayload = (encryptedPayload, secretKey, vector) => {\r\n try {\r\n const ciphertext = CryptoJS.enc.Base64.parse(encryptedPayload);\r\n const key = CryptoJS.enc.Utf8.parse(secretKey);\r\n const initializationVector = CryptoJS.enc.Utf8.parse(vector);\r\n\r\n const decrypted = CryptoJS.AES.decrypt({ ciphertext }, key, {\r\n iv: initializationVector,\r\n mode: CryptoJS.mode.CBC,\r\n padding: CryptoJS.pad.Pkcs7,\r\n });\r\n\r\n const decryptedPayload = decrypted.toString(CryptoJS.enc.Utf8);\r\n const json = JSON.parse(decryptedPayload);\r\n\r\n return json;\r\n } catch (error) {\r\n console.error(\"Error decrypting payload:\", error.message);\r\n }\r\n };\r\n\r\n return { getCourseContentGuide };\r\n};\r\n\r\nexport default ApiService;\r\n","import React, { Component } from \"react\";\r\nimport ContentSection from \"../../components/Content-Section\";\r\nimport ResponsiveHtml from \"components/Common/responsive-html-renderer/responsive-html\";\r\nimport ApiService from \"./services/api-service\";\r\n\r\nclass PrintCourseContentGuide extends Component {\r\n state = {\r\n sectionId: 0,\r\n sections: [],\r\n sectionCount: 0,\r\n };\r\n\r\n componentDidMount() {\r\n const { match } = this.props;\r\n this.loadCourseContent(match.params.token);\r\n }\r\n\r\n loadCourseContent = async (userCourseToken) => {\r\n const apiService = ApiService();\r\n\r\n const contentGuide = await apiService.getCourseContentGuide(\r\n userCourseToken\r\n );\r\n\r\n const sectionCount = contentGuide.sections.length;\r\n\r\n let sections = [];\r\n\r\n for (let i = 1; i <= sectionCount; i++) {\r\n const section = this.getSection(contentGuide.sections, i);\r\n\r\n if (section != null) {\r\n sections.push(section);\r\n }\r\n }\r\n\r\n this.setState({\r\n sections: sections,\r\n sectionCount: sectionCount,\r\n });\r\n };\r\n\r\n getSection = (sections, sectionNumber) => {\r\n return sections.find((x) => x.sectionId === sectionNumber);\r\n };\r\n\r\n getSectionStyle = (sectionNumber) => {\r\n return sectionNumber === 0 ? {} : { paddingTop: \"160px\" };\r\n };\r\n\r\n getTableOfContents = () => {\r\n let items = [];\r\n\r\n for (let i = 1; i <= this.state.sections.length; i++) {\r\n items.push(\r\n \r\n Section {i} \r\n \r\n );\r\n }\r\n\r\n items.push(\r\n \r\n How to save for offline use \r\n \r\n );\r\n\r\n return items;\r\n };\r\n\r\n render() {\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n Table of Contents \r\n {this.getTableOfContents()} \r\n \r\n\r\n {this.state.sections.map((section, a) => (\r\n \r\n {section.content.map((content, i) => (\r\n
\r\n \r\n \r\n
\r\n \r\n ))}\r\n
\r\n ))}\r\n\r\n \r\n
\r\n How to save for offline use \r\n \r\n You can come back to the Food Safety Education website anytime to\r\n access your course guide. We would encourage you not save or print\r\n this material as it does change from time to time. By coming back,\r\n you are always guaranteed to have access to the very latest course\r\n guide.\r\n
\r\n \r\n If you wish to save a copy to read later, you can save this page,\r\n or print to PDF. If you are using a browser, such as Google\r\n Chrome, you can save the page to read later.{\" \"}\r\n \r\n Click here for instructions on how to save this page in Google\r\n Chrome\r\n \r\n .\r\n
\r\n \r\n
\r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default PrintCourseContentGuide;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Modal,\r\n ModalHeader,\r\n ModalBody,\r\n ModalFooter,\r\n Form,\r\n Row,\r\n Col,\r\n FormGroup,\r\n} from \"reactstrap\";\r\nimport { userTypes } from \"../../../../constants\";\r\nimport formHandler from \"../../../../components/Common/Fields/form-handler\";\r\nimport \"../../../../components/Common/Fields/Fields.scss\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\nimport InputField from \"../../../../components/Common/Fields/Input-Field\";\r\nimport SelectField from \"../../../../components/Common/Fields/Select-Field\";\r\nimport * as validators from \"../../../../components/Common/Fields/Validators/Field-Validators\";\r\n\r\nconst emailValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (validators.email(value)) return validators.email(value);\r\n\r\n return false;\r\n};\r\n\r\nconst validateSelect = (fieldName, value) => {\r\n if (validators.required(fieldName, value) || value === \"-1\") {\r\n return `${fieldName} is required.`;\r\n }\r\n return false;\r\n};\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n toggleEditDialog,\r\n onFieldError,\r\n onDialogInputChange,\r\n onEdit,\r\n dialogs,\r\n isProcessing,\r\n fields,\r\n } = this.props;\r\n const { firstName, lastName, email, active, userType } = fields;\r\n const form = formHandler();\r\n return (\r\n \r\n \r\n toggleEditDialog()}>Edit User \r\n \r\n \r\n \r\n \r\n \r\n form.validate({\r\n validFn: () => {\r\n onEdit(fields);\r\n },\r\n })\r\n }\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Save\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n dialogs,\r\n toggleDeleteDialog,\r\n fields,\r\n onDelete,\r\n isProcessing\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete Use\r\n \r\n \r\n \r\n Are you sure you want to delete this user? Please note, this will\r\n delete any courses or vouchers attached to this user. This cannot\r\n be undone.\r\n \r\n \r\n \r\n {\r\n onDelete(fields);\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import SolvableDataTable from \"../../../components/solvable-datatable/solvable-datatable\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport React, { Component } from \"react\";\r\nimport EditDialog from \"./Modals/edit\";\r\nimport DeleteDialog from \"./Modals/delete\";\r\n\r\nclass DataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n settings: {},\r\n };\r\n this.actionButtonHandler = this.actionButtonHandler.bind(this);\r\n }\r\n\r\n onSettingsChanged = (settings) => {\r\n this.setState({ settings });\r\n };\r\n\r\n columns = [\r\n {\r\n Header: \"First Name\",\r\n accessor: \"firstName\",\r\n searchable: true,\r\n },\r\n {\r\n accessor: \"userId\",\r\n show: false,\r\n },\r\n {\r\n accessor: \"loginAsUserToken\",\r\n show: false,\r\n },\r\n {\r\n Header: \"Last Name\",\r\n accessor: \"lastName\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Email\",\r\n accessor: \"email\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Active\",\r\n accessor: \"active\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"User Type\",\r\n accessor: \"userType\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Date Registered\",\r\n accessor: \"registeredDateTime\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Last Login\",\r\n accessor: \"lastLoginDateTime\",\r\n searchable: true,\r\n },\r\n ];\r\n\r\n actionButtonHandler = (evt) => {\r\n const { toggleEditDialog, toggleDeleteDialog } = this.props;\r\n switch (evt.type) {\r\n case \"button1\":\r\n toggleEditDialog(evt.data);\r\n break;\r\n case \"button2\":\r\n toggleDeleteDialog(evt.data);\r\n break;\r\n case \"button3\":\r\n this.props.history.push(`/Admin/User-Courses/${evt.data.userId}`);\r\n break;\r\n }\r\n };\r\n\r\n render() {\r\n const {\r\n toggleEditDialog,\r\n toggleDeleteDialog,\r\n onFieldError,\r\n onDelete,\r\n onEdit,\r\n dataTable,\r\n dialog,\r\n onSettingsChanged,\r\n onDialogInputChange,\r\n } = this.props;\r\n const { data, isProcessing, settings } = dataTable;\r\n const { dialogs, fields, isProcessing: isDialogProcessing } = dialog;\r\n return (\r\n \r\n \r\n \r\n \r\n {\r\n return `/login/${row.userId}/${row.loginAsUserToken}`;\r\n },\r\n },\r\n ],\r\n }}\r\n keepSettings={true}\r\n stateSettings={settings}\r\n onSettingsChanged={onSettingsChanged}\r\n onActionButtonClick={this.actionButtonHandler}\r\n data={data}\r\n />\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default DataTable;\r\n","import React, { Component } from \"react\";\r\nimport Select from \"react-select\";\r\nimport PropTypes from \"prop-types\";\r\nimport \"./Fields.scss\";\r\nimport debounce from \"lodash/debounce\";\r\n\r\nconst EVENT_DEBOUNCE = 2000;\r\n\r\nclass ReactSelectField extends Component {\r\n static propTypes = {\r\n keepSettings: PropTypes.bool,\r\n name: PropTypes.string.isRequired,\r\n showSelectAll: PropTypes.bool,\r\n selectAllByDefault: PropTypes.bool,\r\n validate: PropTypes.func,\r\n onChange: PropTypes.func.isRequired,\r\n onFieldError: PropTypes.func,\r\n enableFieldColorError: PropTypes.bool,\r\n enableFieldErrorMessage: PropTypes.bool,\r\n enableFieldErrorNotification: PropTypes.bool\r\n };\r\n\r\n static defaultProps = {\r\n keepSettings: false,\r\n showSelectAll: false,\r\n selectAllByDefault: false,\r\n enableFieldColorError: true,\r\n enableFieldErrorMessage: false,\r\n enableFieldErrorNotification: true,\r\n onFieldError: () => {}\r\n };\r\n\r\n state = {\r\n error: false,\r\n options: this.props.options,\r\n value: this.props.keepSettings\r\n ? this.props.value.length > 0\r\n ? this.props.value\r\n : this.props.options\r\n : this.props.selectAllByDefault\r\n ? this.props.options\r\n : null\r\n };\r\n\r\n _isMounted = false;\r\n\r\n constructor(props) {\r\n super(props);\r\n this.debouncedCallback = debounce(\r\n error => this.fireFieldErrorEvent(error),\r\n EVENT_DEBOUNCE\r\n );\r\n }\r\n\r\n componentDidMount() {\r\n this._isMounted = true;\r\n if (this.props.selectAllByDefault && !this.props.keepSettings) {\r\n this.onChange(this.state.options);\r\n } else {\r\n this.onChange(this.state.value);\r\n }\r\n\r\n //Option to add 'Select All' option item.\r\n if (this.props.showSelectAll) {\r\n let additionalOption = { value: \"*\", label: \"Select All\" };\r\n this.setState({\r\n ...this.state,\r\n options: [additionalOption, ...this.state.options]\r\n });\r\n }\r\n }\r\n\r\n componentWillUnmount() {\r\n this._isMounted = false;\r\n }\r\n\r\n static getDerivedStateFromProps(props, state) {\r\n return { defaultValue: props.defaultValue };\r\n }\r\n\r\n onChange = value => {\r\n this._detectChange(value);\r\n };\r\n\r\n onKeyPress = evt => {\r\n if (evt.key === \"Enter\" && this.props.onKeyPress) {\r\n this.props.onKeyPress();\r\n }\r\n };\r\n\r\n onBlur = () => {\r\n this._validateField();\r\n };\r\n\r\n _detectChange = value => {\r\n const name = this.props.name;\r\n const error = this.props.validate ? this.props.validate(value) : false;\r\n\r\n if (error) this.debouncedCallback(value, error);\r\n\r\n if (this.props.showSelectAll && value) {\r\n value = value.find(v => v.value === \"*\")\r\n ? this.state.options.filter(v => v.value !== \"*\")\r\n : value;\r\n }\r\n\r\n this.setState({ value, error });\r\n this.props.onChange({ name, value, error });\r\n return error;\r\n };\r\n\r\n fireFieldErrorEvent = error => this.props.onFieldError(error);\r\n\r\n // Note: Internal function, used by this component\r\n _validateField = () => {\r\n if (!this._isMounted) {\r\n return;\r\n }\r\n let error = this._detectChange(this.state.value);\r\n if (error) this.debouncedCallback(null, error);\r\n return { name: this.props.name, error: error };\r\n };\r\n\r\n _isValidComponentInstance = () => {\r\n return this._isMounted;\r\n };\r\n\r\n render() {\r\n const {\r\n validate,\r\n enableFieldColorError,\r\n enableFieldErrorMessage,\r\n enableFieldErrorNotification,\r\n onFieldError,\r\n ...other\r\n } = this.props;\r\n\r\n return (\r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default ReactSelectField;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Card,\r\n CardBody,\r\n CardFooter,\r\n CardHeader,\r\n Row,\r\n Col,\r\n Collapse,\r\n Form,\r\n FormGroup,\r\n} from \"reactstrap\";\r\nimport { userTypes as userTypesList } from \"../../../constants\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport ReactSelectField from \"../../../components/Common/Fields/React-Select-Field\";\r\nimport DatePickerField from \"../../../components/Common/Fields/Date-Picker-Field\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport withSizes from \"react-sizes\";\r\n\r\nclass FilterSection extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n showFilters: false,\r\n };\r\n }\r\n\r\n toggle = () => {\r\n this.setState({\r\n showFilters: !this.state.showFilters,\r\n });\r\n };\r\n\r\n render() {\r\n const form = formHandler();\r\n const { isProcessing } = this.props.dataTable;\r\n const { userTypes, startDate, endDate } = this.props.dataTable.fields;\r\n const { showFilters } = this.state;\r\n const { onInputChange, onFieldError, loadRequest, reset } = this.props;\r\n return (\r\n \r\n
\r\n \r\n \r\n Filter Registers \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n form.validate({\r\n validFn: () => loadRequest(this.props.dataTable.fields),\r\n });\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Filter\r\n \r\n reset()}\r\n className=\"ttg-blue-btn ml-2\"\r\n isLoading={isProcessing}\r\n >\r\n Reset\r\n \r\n \r\n \r\n \r\n
\r\n form.validate({\r\n validFn: () => loadRequest(this.props.dataTable.fields),\r\n })\r\n }\r\n />\r\n \r\n );\r\n }\r\n}\r\n\r\nconst mapSizesToProps = ({ width }) => ({\r\n isMobile: width < 800,\r\n});\r\n\r\nexport default withSizes(mapSizesToProps)(FilterSection);\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport Datatable from \"./datatable\";\r\nimport FilterSection from \"./filter-section\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\n\r\nclass Users extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoad } = this.props;\r\n onLoad();\r\n\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n const { isProcessing, isReset } = this.props.dataTable;\r\n return (\r\n <>\r\n \r\n \r\n Registers \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default Users;\r\n","import HttpClient from \"../../../../coreLib//http/httpClient\";\r\nimport moment from \"moment\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const load = (payload) => {\r\n return httpClient.post(\"v1/admin/users\", {\r\n ...payload,\r\n startDate: moment(payload.startDate),\r\n endDate: moment(payload.endDate),\r\n userTypes: payload.userTypes.map((u) => {\r\n return typeof u === \"object\" ? u.value : u;\r\n }),\r\n });\r\n };\r\n\r\n const editUser = (payload) => {\r\n let model = {\r\n firstName: payload.firstName,\r\n lastName: payload.lastName,\r\n email: payload.email,\r\n active:\r\n payload.active === \"Yes\" ||\r\n payload.active === true ||\r\n payload.active === \"true\"\r\n ? true\r\n : false,\r\n userType: parseInt(payload.userType),\r\n };\r\n return httpClient.put(`v1/admin/users/${payload.userId}`, model);\r\n };\r\n\r\n const deleteUser = (userId) => {\r\n return httpClient.delete(`v1/admin/users/${userId}`);\r\n };\r\n\r\n return {\r\n load,\r\n editUser,\r\n deleteUser,\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\nimport moment from \"moment\";\r\n\r\nexport const onLoad = () => (dispatch, getState) => {\r\n let fieldValues = getState().users.DataTable.fields;\r\n let params = fieldValues ? fieldValues : getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const resetData = () => dispatch => {\r\n let params = getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const loadRequest = params => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_USERS_ONLOAD_REQUEST });\r\n service\r\n .load(params)\r\n .then(resp => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n });\r\n};\r\n\r\nconst getInitialParams = () => {\r\n return {\r\n userTypes: [1, 2, 3],\r\n startDate: moment().subtract(12, \"months\")._d,\r\n endDate: moment()._d\r\n };\r\n};\r\n\r\nexport const reset = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_USERS_RESET });\r\n dispatch(resetData());\r\n};\r\n\r\nconst onLoadSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_ONLOAD_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onLoadFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_ONLOAD_FAILURE\r\n });\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_USERS_FILTER_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n\r\nexport const keepDataTableSettings = settings => ({\r\n type: ActionTypes.ADMIN_USERS_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings\r\n }\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.ADMIN_USERS_DATATABLE_CLEAR_SEARCHBOX,\r\n});","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport HttpService from \"../service\";\r\n\r\nexport const onDelete = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_USERS_DELETE_REQUEST });\r\n service\r\n .deleteUser(payload.userId)\r\n .then(() => {\r\n dispatch(onDeleteSuccess(payload));\r\n dispatch(addNotification(\"User has been successfully deleted.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onDeleteFailure());\r\n dispatch(\r\n addNotification(\"There was an error deleting the user\", \"warning\")\r\n );\r\n });\r\n};\r\n\r\nconst onDeleteSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_DELETE_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nexport const onEdit = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_USERS_EDIT_REQUEST });\r\n service\r\n .editUser(payload)\r\n .then(() => {\r\n dispatch(onEditSuccess(payload));\r\n dispatch(addNotification(\"User has been successfully edited.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onEditFailure());\r\n dispatch(\r\n addNotification(\"There was an error updating the user\", \"warning\")\r\n );\r\n });\r\n};\r\n\r\nconst onEditSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_EDIT_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onEditFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_EDIT_FAILURE\r\n });\r\n};\r\n\r\nconst onDeleteFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_DELETE_FAILURE\r\n });\r\n};\r\n\r\nexport const toggleDeleteDialog = payload => ({\r\n type: ActionTypes.ADMIN_USERS_SHOW_DELETE_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleEditDialog = payload => ({\r\n type: ActionTypes.ADMIN_USERS_SHOW_EDIT_DIALOG,\r\n payload\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_USERS_DIALOG_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport Users from \"./users\";\r\nimport * as dataTableActionCreators from \"./redux/datatable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.users.DataTable,\r\n dialog: state.users.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoad: () => dispatch(dataTableActionCreators.onLoad()),\r\n reset: () => dispatch(dataTableActionCreators.reset()),\r\n toggleEditDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleEditDialog(payload)),\r\n toggleDeleteDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleDeleteDialog(payload)),\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(dataTableActionCreators.formInputChange(name, value, error));\r\n },\r\n onDialogInputChange: ({ name, value, error }) => {\r\n dispatch(dialogActionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n onDelete: (payload) => dispatch(dialogActionCreators.onDelete(payload)),\r\n onEdit: (payload) => dispatch(dialogActionCreators.onEdit(payload)),\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n loadRequest: payload => {\r\n dispatchProps.dispatch(dataTableActionCreators.loadRequest(payload));\r\n }\r\n});\r\n\r\nconst UsersContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n )(Users)\r\n);\r\n\r\nexport default UsersContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n toggleDeleteDialog,\r\n dialogs,\r\n onDelete,\r\n fields,\r\n isProcessing\r\n } = this.props;\r\n return (\r\n \r\n \r\n Delete User \r\n \r\n \r\n Are you sure you want to delete this user’s course? Please note,\r\n this cannot be undone.\r\n \r\n \r\n \r\n onDelete(fields)}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import SolvableDataTable from \"../../../components/solvable-datatable/solvable-datatable\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport React, { Component } from \"react\";\r\nimport DeleteDialog from \"./Modals/delete\";\r\n\r\nclass DataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n settings: {},\r\n };\r\n this.actionButtonHandler = this.actionButtonHandler.bind(this);\r\n }\r\n\r\n columns = [\r\n {\r\n Header: \"First Name\",\r\n accessor: \"firstName\",\r\n searchable: true,\r\n },\r\n {\r\n accessor: \"userCourseId\",\r\n show: false,\r\n },\r\n {\r\n accessor: \"loginAsUserToken\",\r\n show: false,\r\n },\r\n {\r\n Header: \"Last Name\",\r\n accessor: \"lastName\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Email\",\r\n accessor: \"email\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Enrolled Date/Time\",\r\n accessor: \"enrolmentDateTime\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Course Title\",\r\n accessor: \"courseTitle\",\r\n searchable: true,\r\n },\r\n {\r\n Header: \"Certificate Number\",\r\n accessor: \"certificateNumber\",\r\n searchable: true,\r\n },\r\n ];\r\n\r\n actionButtonHandler = (evt) => {\r\n const { toggleDeleteDialog, downloadTaxInvoice } = this.props;\r\n switch (evt.type) {\r\n case \"button1\":\r\n this.props.history.push(\r\n `/Admin/Edit-User-Course/${evt.data.userCourseId}`\r\n );\r\n break;\r\n case \"button2\":\r\n toggleDeleteDialog(evt.data);\r\n break;\r\n case \"button3\":\r\n downloadTaxInvoice(evt.data.invoiceGuid);\r\n break;\r\n }\r\n };\r\n\r\n render() {\r\n const {\r\n dataTable,\r\n onDelete,\r\n toggleDeleteDialog,\r\n dialog,\r\n onSettingsChanged,\r\n } = this.props;\r\n const { data, isProcessing, settings } = dataTable;\r\n const { dialogs, fields, isProcessing: isDialogProcessing } = dialog;\r\n return (\r\n \r\n \r\n \r\n row._original.invoiceGuid === null,\r\n },\r\n {\r\n target: \"button4\",\r\n icon: \"fas fa-address-card\",\r\n tooltip:\r\n \"You can right click “Open link in incognito window” to avoid having to log out and in again\",\r\n to: (row) => {\r\n return `/login/${row.userId}/${row.loginAsUserToken}`;\r\n },\r\n },\r\n ],\r\n }}\r\n keepSettings={true}\r\n stateSettings={settings}\r\n onSettingsChanged={onSettingsChanged}\r\n onActionButtonClick={this.actionButtonHandler}\r\n data={data}\r\n />\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default DataTable;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Card,\r\n CardBody,\r\n CardFooter,\r\n CardHeader,\r\n Input,\r\n Row,\r\n Col,\r\n Collapse,\r\n Form,\r\n FormGroup,\r\n} from \"reactstrap\";\r\nimport CourseService from \"../../../services/course-service\";\r\nimport ReactSelectField from \"../../../components/Common/Fields/React-Select-Field\";\r\nimport DatePickerField from \"../../../components/Common/Fields/Date-Picker-Field\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nclass FilterSection extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n showFilters: false,\r\n };\r\n }\r\n\r\n toggle = () => {\r\n this.setState({\r\n showFilters: !this.state.showFilters,\r\n });\r\n };\r\n\r\n render() {\r\n const { showFilters } = this.state;\r\n const form = formHandler();\r\n const {\r\n dataTable,\r\n onInputChange,\r\n onFieldError,\r\n onLoad,\r\n reset,\r\n } = this.props;\r\n const { isProcessing } = dataTable;\r\n const { courseIds, startDate, endDate } = dataTable.fields;\r\n\r\n const courses = CourseService()\r\n .getCourses()\r\n .map((course) => {\r\n return {\r\n label: course.courseTitle,\r\n value: course.courseId,\r\n };\r\n });\r\n return (\r\n \r\n
\r\n \r\n \r\n Filter Course Enrolments \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n {\r\n form.validate({\r\n validFn: () => onLoad(dataTable.fields),\r\n });\r\n }}\r\n type=\"submit\"\r\n className=\"ttg-btn\"\r\n isLoading={false}\r\n >\r\n Filter\r\n \r\n\r\n reset()}\r\n className=\"ttg-blue-btn ml-2\"\r\n isLoading={isProcessing}\r\n >\r\n Reset\r\n \r\n \r\n \r\n \r\n
\r\n form.validate({\r\n validFn: () => onLoad(dataTable.fields),\r\n })\r\n }\r\n />\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default FilterSection;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport Datatable from \"./datatable\";\r\nimport FilterSection from \"./filter-section\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\n\r\nclass Users extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const {\r\n onLoad,\r\n match,\r\n hideFilterSection,\r\n onLoadSpecificUserCourse,\r\n } = this.props;\r\n match.params.id ? hideFilterSection(true) : hideFilterSection(false);\r\n match.params.id ? onLoadSpecificUserCourse(match.params.id) : onLoad();\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n const { isProcessing, hideFilterSection, isReset } = this.props.dataTable;\r\n return (\r\n <>\r\n \r\n \r\n Course Enrolments \r\n \r\n \r\n {!isReset && (\r\n \r\n \r\n \r\n )}\r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default Users;\r\n","import HttpClient from \"../../../../coreLib//http/httpClient\";\r\nimport moment from \"moment\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const loadCourses = payload => {\r\n let model = {\r\n courseIds: payload.courseIds.map(course =>\r\n typeof course === \"object\" ? course.value : course\r\n ),\r\n startDate: moment(payload.startDate),\r\n endDate: moment(payload.endDate)\r\n };\r\n return httpClient.post(\"v1/admin/users/courses\", model);\r\n };\r\n\r\n const loadSpecificUserCourses = id => {\r\n return httpClient.get(`v1/admin/users/courses/${id}`);\r\n };\r\n\r\n const deleteCourse = id => {\r\n return httpClient.delete(`v1/admin/users/course/${id}`);\r\n };\r\n\r\n const downloadTaxInvoice = invoiceId => {\r\n return httpClient.get(`v1/userCourse/pdf/tax-invoice/${invoiceId}`, {\r\n responseType: \"blob\"\r\n });\r\n };\r\n\r\n return {\r\n loadCourses,\r\n loadSpecificUserCourses,\r\n deleteCourse,\r\n downloadTaxInvoice\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport CourseService from \"../../../../../services/course-service\";\r\nimport moment from \"moment\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nexport const onLoad = () => (dispatch, getState) => {\r\n let fieldValues = getState().userCourses.DataTable.fields;\r\n let params = fieldValues ? fieldValues : getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const loadRequest = (params) => (dispatch) => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_USER_COURSES_ONLOAD_REQUEST });\r\n service\r\n .loadCourses(params)\r\n .then((resp) => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n });\r\n};\r\n\r\nexport const resetData = () => (dispatch) => {\r\n let params = getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const onLoadSpecificUserCourse = (id) => (dispatch) => {\r\n let service = HttpService();\r\n\r\n service\r\n .loadSpecificUserCourses(id)\r\n .then((resp) => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(addNotification(\"Error loading Course Enrolments.\", \"warning\"));\r\n });\r\n};\r\n\r\nexport const reset = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_USERS_COURSES_RESET });\r\n dispatch(resetData());\r\n};\r\n\r\nconst onLoadFailure = () => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USER_COURSES_ONLOAD_FAILURE,\r\n });\r\n};\r\n\r\nconst getInitialParams = () => {\r\n return {\r\n courseIds: CourseService()\r\n .getCourses()\r\n .map((course) => course.courseId),\r\n startDate: moment().subtract(12, \"months\")._d,\r\n endDate: moment()._d,\r\n };\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error,\r\n },\r\n});\r\n\r\nconst onLoadSuccess = (payload) => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USER_COURSES_ONLOAD_SUCCESS,\r\n payload,\r\n });\r\n};\r\n\r\nexport const hideFilterSection = (payload) => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_HIDE_FILTER_SECTION,\r\n payload,\r\n});\r\n\r\nexport const downloadTaxInvoice = (invoidGuid) => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USERS_COURSES_DOWNLOAD_TAX_INVOICE_REQUEST,\r\n });\r\n let service = HttpService();\r\n service\r\n .downloadTaxInvoice(invoidGuid)\r\n .then((resp) => {\r\n dispatch(onDownloadTaxInvoiceSuccess());\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"taxinvoice.pdf\");\r\n })\r\n .catch(() => {\r\n dispatch(onDownloadTaxInvoiceFailure());\r\n dispatch(addNotification(\"Unable to download tax invoice.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onDownloadTaxInvoiceSuccess = () => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_DOWNLOAD_TAX_INVOICE_SUCCESS,\r\n});\r\n\r\nconst onDownloadTaxInvoiceFailure = () => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_DOWNLOAD_TAX_INVOICE_FAILURE,\r\n});\r\n\r\nexport const keepDataTableSettings = (settings) => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings,\r\n },\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.ADMIN_USERS_COURSES_DATATABLE_CLEAR_SEARCHBOX,\r\n});\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\n\r\nexport const onDelete = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_USER_COURSES_DELETE_REQUEST });\r\n service\r\n .deleteCourse(payload.userCourseId)\r\n .then(() => {\r\n dispatch(onDeleteSuccess(payload));\r\n dispatch(addNotification(\"User course has been successfully deleted.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onDeleteFailure());\r\n dispatch(addNotification(\"Unable to delete the user course.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onDeleteSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_USER_COURSES_DELETE_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onDeleteFailure = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_USER_COURSES_DELETE_FAILURE });\r\n};\r\n\r\nexport const toggleDeleteDialog = payload => ({\r\n type: ActionTypes.ADMIN_USER_COURSES_SHOW_DELETE_DIALOG,\r\n payload\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport UsersCourse from \"./users-course\";\r\nimport * as dataTableActionCreators from \"./redux/datatable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.userCourses.DataTable,\r\n dialog: state.userCourses.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoad: (payload) => dispatch(dataTableActionCreators.onLoad(payload)),\r\n reset: () => dispatch(dataTableActionCreators.reset()),\r\n onLoadSpecificUserCourse: (id) =>\r\n dispatch(dataTableActionCreators.onLoadSpecificUserCourse(id)),\r\n toggleDeleteDialog: (payload) => {\r\n dispatch(dialogActionCreators.toggleDeleteDialog(payload));\r\n },\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(dataTableActionCreators.formInputChange(name, value, error));\r\n },\r\n hideFilterSection: (payload) => {\r\n dispatch(dataTableActionCreators.hideFilterSection(payload));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n onDelete: (payload) => dispatch(dialogActionCreators.onDelete(payload)),\r\n downloadTaxInvoice: (invoiceGuid) =>\r\n dispatch(dataTableActionCreators.downloadTaxInvoice(invoiceGuid)),\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst UsersCourseContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n )(UsersCourse)\r\n);\r\n\r\nexport default UsersCourseContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Input } from \"reactstrap\";\r\nimport PropTypes from \"prop-types\";\r\nimport \"./Fields.scss\";\r\nimport debounce from \"lodash/debounce\";\r\n\r\nconst EVENT_DEBOUNCE = 2000;\r\n\r\nclass TextAreaField extends Component {\r\n static propTypes = {\r\n placeholder: PropTypes.string,\r\n name: PropTypes.string.isRequired,\r\n value: PropTypes.string,\r\n validate: PropTypes.func,\r\n onChange: PropTypes.func.isRequired,\r\n onFieldError: PropTypes.func,\r\n enableFieldColorError: PropTypes.bool,\r\n enableFieldErrorMessage: PropTypes.bool,\r\n enableFieldErrorNotification: PropTypes.bool,\r\n rows: PropTypes.number,\r\n };\r\n\r\n static defaultProps = {\r\n enableFieldColorError: true,\r\n enableFieldErrorMessage: false,\r\n enableFieldErrorNotification: true,\r\n rows: 4,\r\n onFieldError: () => {},\r\n };\r\n\r\n state = {\r\n value: this.props.value,\r\n error: false,\r\n };\r\n\r\n _isMounted = false;\r\n\r\n constructor(props) {\r\n super(props);\r\n this.debouncedCallback = debounce(\r\n (evt, error) => this.fireFieldErrorEvent(error),\r\n EVENT_DEBOUNCE\r\n );\r\n }\r\n\r\n componentDidMount() {\r\n this._isMounted = true;\r\n }\r\n\r\n componentWillUnmount() {\r\n this._isMounted = false;\r\n }\r\n\r\n static getDerivedStateFromProps(props, state) {\r\n return { value: props.value };\r\n }\r\n\r\n onChange = (evt) => {\r\n this._detectChange(evt.target.value);\r\n };\r\n\r\n onKeyPress = (evt) => {\r\n if (evt.key === \"Enter\" && this.props.onKeyPress) {\r\n this.props.onKeyPress();\r\n }\r\n };\r\n\r\n onBlur = (evt) => {\r\n let error = this._detectChange(evt.target.value);\r\n\r\n // Persist react synthetic event\r\n evt.persist();\r\n if (error) this.debouncedCallback(evt, error);\r\n };\r\n\r\n _detectChange = (value) => {\r\n const name = this.props.name;\r\n //const value = evt.target.value;\r\n const error = this.props.validate ? this.props.validate(value) : false;\r\n\r\n this.setState({ value, error });\r\n this.props.onChange({ name, value, error });\r\n\r\n return error;\r\n };\r\n\r\n fireFieldErrorEvent = (error) => this.props.onFieldError(error);\r\n\r\n // Note: Internal function, used by this component\r\n _validateField = () => {\r\n if (!this._isMounted) {\r\n return;\r\n }\r\n let error = this._detectChange(this.state.value);\r\n if (error) this.debouncedCallback(null, error);\r\n return { name: this.props.name, error: error };\r\n };\r\n\r\n _isValidComponentInstance = () => {\r\n return this._isMounted;\r\n };\r\n\r\n render() {\r\n const {\r\n validate,\r\n enableFieldColorError,\r\n enableFieldErrorMessage,\r\n enableFieldErrorNotification,\r\n rows,\r\n onFieldError,\r\n ...other\r\n } = this.props;\r\n\r\n return (\r\n <>\r\n \r\n {this.state.error && enableFieldErrorMessage && (\r\n {this.state.error} \r\n )}\r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default TextAreaField;\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n toggleDeleteDialog,\r\n showDeleteDialog,\r\n isDeleting,\r\n deleteCourse,\r\n fields\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete User Course\r\n \r\n \r\n \r\n Are you sure you want to delete this user course? Please note,\r\n this will delete any courses or vouchers attached to this user.\r\n This cannot be undone.\r\n \r\n \r\n \r\n deleteCourse(fields)}\r\n className=\"ttg-btn\"\r\n isLoading={isDeleting}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport { Row, Col, Form, FormGroup, Button } from \"reactstrap\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport Textarea from \"../../../components/Common/Fields/Text-Area-Field\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport AddressEntry from \"../../../components/Address-Entry/Address-Entry\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport InputField from \"../../../components/Common/Fields/Input-Field\";\r\nimport MaskedInputField from \"../../../components/Common/Fields/Masked-Input-Field\";\r\nimport CheckboxField from \"../../../components/Common/Fields/Checkbox-Field\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport DeleteDialog from \"./delete-dialog\";\r\nimport ConfirmModal from \"./../../../components/Common/Confirm-Modal/Confirm-Modal\";\r\n\r\nconst validateUsiNumber = (fieldName, value) => {\r\n if (validators.required(fieldName, value) || value === \"-1\") {\r\n return `${fieldName} is required.`;\r\n }\r\n if (!/^[2-9A-HJ-NP-Za-hj-np-z]{10}$/.test(value) && value !== \"INDIV\") {\r\n return `${value} is not a valid USI number.`;\r\n }\r\n return false;\r\n};\r\n\r\nconst emailValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n if (validators.email(value)) return validators.email(value);\r\n\r\n return false;\r\n};\r\n\r\nconst phoneValidator = (fieldName, value) => {\r\n if (validators.required(fieldName, value))\r\n return validators.required(fieldName, value);\r\n\r\n if (validators.phone(value)) return validators.phone(value);\r\n\r\n return false;\r\n};\r\n\r\nconst getPhoneMask = (value) => {\r\n if (\r\n value.startsWith(\"02\") ||\r\n value.startsWith(\"03\") ||\r\n value.startsWith(\"07\") ||\r\n value.startsWith(\"08\")\r\n )\r\n return \"99 9999 9999\";\r\n\r\n return \"9999 999 999\";\r\n};\r\n\r\nclass Users extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoad, match } = this.props;\r\n onLoad(match.params.userCourseId);\r\n }\r\n\r\n render() {\r\n const {\r\n isProcessing,\r\n fields,\r\n onInputChange,\r\n onFieldError,\r\n updateCourse,\r\n toggleDeleteDialog,\r\n isDeleting,\r\n deleteCourse,\r\n showDeleteDialog,\r\n showCourseTransferConfirmation,\r\n onCourseTransferConfirmation,\r\n toggleCourseTransferConfirmation,\r\n } = this.props;\r\n const {\r\n firstName,\r\n lastName,\r\n usiNumber,\r\n email,\r\n phone,\r\n unitNumber,\r\n streetNumber,\r\n streetName,\r\n city,\r\n state,\r\n postcode,\r\n enrolmentStep2Completed,\r\n enrolmentStep3Completed,\r\n thirdPartyFormCompleted,\r\n surveyCompleted,\r\n courseCompleted,\r\n redirectToQuiz,\r\n setCount,\r\n lastSectionCompleted,\r\n lastQuestionCompleted,\r\n previousCertificateNumber,\r\n nswCertificateDetails,\r\n comments,\r\n } = fields;\r\n const form = formHandler();\r\n return (\r\n <>\r\n \r\n \r\n \r\n Edit User Course \r\n \r\n \r\n \r\n \r\n\r\n \r\n\r\n \r\n onCourseTransferConfirmation(evt, fields.userCourseId)\r\n }\r\n >\r\n Are you sure you want to transfer this user course to a new user\r\n matching the details of the user course? Note: this cannot be\r\n undone.\r\n \r\n\r\n \r\n form.validate({\r\n validFn: () => updateCourse(fields),\r\n })\r\n }\r\n />\r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default Users;\r\n","import HttpClient from \"../../../../coreLib/http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const loadCourse = (payload) => {\r\n return httpClient.get(`v1/admin/users/course/${payload}`);\r\n };\r\n\r\n const updateCourse = (payload) => {\r\n let model = {\r\n ...payload,\r\n enrolmentStep2Completed: getValue(payload.enrolmentStep2Completed),\r\n enrolmentStep3Completed: getValue(payload.enrolmentStep3Completed),\r\n thirdPartyFormCompleted: getValue(payload.thirdPartyFormCompleted),\r\n surveyCompleted: getValue(payload.surveyCompleted),\r\n courseCompleted: getValue(payload.courseCompleted),\r\n redirectToQuiz: getValue(payload.redirectToQuiz),\r\n };\r\n return httpClient.put(\r\n `v1/admin/users/course/${payload.userCourseId}`,\r\n model\r\n );\r\n };\r\n\r\n const getValue = (itm) => (itm || itm === \"on\" ? true : false);\r\n\r\n const deleteCourse = (userCourseId) =>\r\n httpClient.delete(`v1/admin/users/course/${userCourseId}`);\r\n\r\n const transferUserCourse = (userCourseId) =>\r\n httpClient.post(`v1/admin/users/courses/${userCourseId}/reassignment`);\r\n\r\n return {\r\n loadCourse,\r\n deleteCourse,\r\n updateCourse,\r\n transferUserCourse,\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../services/api-service\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\n\r\nexport const onLoad = (payload) => (dispatch) => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_ONLOAD_REQUEST });\r\n service\r\n .loadCourse(payload)\r\n .then((resp) => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n dispatch(addNotification(\"Error loading user course.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onLoadSuccess = (payload) => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_EDIT_COURSES_ONLOAD_SUCCESS,\r\n payload,\r\n });\r\n};\r\n\r\nconst onLoadFailure = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_ONLOAD_FAILURE });\r\n};\r\n\r\nexport const updateCourse = (payload) => (dispatch) => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_UPDATE_REQUEST });\r\n service\r\n .updateCourse(payload)\r\n .then((resp) => {\r\n dispatch(onUpdateCourseSuccess());\r\n dispatch(addNotification(\"User course has been successfully updated.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onUpdateCourseFailure());\r\n dispatch(addNotification(\"Unable to update the user course\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onUpdateCourseSuccess = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_UPDATE_SUCCESS });\r\n};\r\n\r\nconst onUpdateCourseFailure = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_UPDATE_FAILURE });\r\n};\r\n\r\nexport const deleteCourse = (payload, history) => (dispatch) => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_DELETE_REQUEST });\r\n service\r\n .deleteCourse(payload.userCourseId)\r\n .then((resp) => {\r\n dispatch(onDeleteCourseSuccess());\r\n dispatch(addNotification(\"User course has been successfully updated.\"));\r\n history.push(\"/admin/User-Courses\");\r\n })\r\n .catch(() => {\r\n dispatch(onDeleteCourseFailure());\r\n dispatch(addNotification(\"Unable to update the user course\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onDeleteCourseSuccess = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_DELETE_SUCCESS });\r\n};\r\n\r\nconst onDeleteCourseFailure = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_DELETE_FAILURE });\r\n};\r\n\r\nexport const toggleDeleteDialog = () => (dispatch) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_SHOW_DELETE_DIALOG });\r\n};\r\n\r\nexport const toggleCourseTransferConfirmation = () => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_EDIT_COURSES_SHOW_COURSE_TRANSFER_CONFIRMATION,\r\n });\r\n};\r\n\r\nexport const handleCourseTransfer = (userCourseId, history) => async (\r\n dispatch\r\n) => {\r\n let service = HttpService();\r\n\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_TRANSFER_REQUEST });\r\n\r\n await service\r\n .transferUserCourse(userCourseId)\r\n .then((resp) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_TRANSFER_SUCCESS });\r\n dispatch(\r\n addNotification(\r\n \"The user course has been successfully transferred to a new user.\"\r\n )\r\n );\r\n\r\n history.push(\"/admin/User-Courses\");\r\n })\r\n .catch((err) => {\r\n dispatch({ type: ActionTypes.ADMIN_EDIT_COURSES_TRANSFER_FAILURE });\r\n\r\n let status = err.response?.status;\r\n let errorMessage = err.response?.data?.Message;\r\n\r\n if (status === 400 && errorMessage) {\r\n dispatch(addNotification(errorMessage, \"warning\"));\r\n return;\r\n }\r\n\r\n dispatch(\r\n addNotification(\r\n \"Unable to transfer the user course to a new user\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_EDIT_COURSES_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport EditUserCourse from \"./edit-user-course\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => state.adminEditCourse;\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoad: (payload) => dispatch(actionCreators.onLoad(payload)),\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n updateCourse: (payload) => dispatch(actionCreators.updateCourse(payload)),\r\n deleteCourse: (payload) =>\r\n dispatch(actionCreators.deleteCourse(payload, ownProps.history)),\r\n toggleDeleteDialog: () => dispatch(actionCreators.toggleDeleteDialog()),\r\n toggleCourseTransferConfirmation: () =>\r\n dispatch(actionCreators.toggleCourseTransferConfirmation()),\r\n onCourseTransferConfirmation: (evt, userCourseId) => {\r\n dispatch(actionCreators.toggleCourseTransferConfirmation());\r\n\r\n if (evt.type !== \"ok\") return;\r\n\r\n dispatch(\r\n actionCreators.handleCourseTransfer(userCourseId, ownProps.history)\r\n );\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst EditUserCourseContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n )(EditUserCourse)\r\n);\r\n\r\nexport default EditUserCourseContainer;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Card,\r\n CardBody,\r\n CardFooter,\r\n CardHeader,\r\n Row,\r\n Col,\r\n Collapse,\r\n Form,\r\n FormGroup\r\n} from \"reactstrap\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport { reportTypes } from \"../../../constants\";\r\nimport DatePickerField from \"../../../components/Common/Fields/Date-Picker-Field\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\nimport SelectField from \"../../../components/Common/Fields/Select-Field\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport orderBy from \"lodash/orderBy\";\r\n\r\nconst validateSelect = (fieldName, value) => {\r\n if (validators.required(fieldName, value) || value === \"-1\") {\r\n return `${fieldName} is required.`;\r\n }\r\n return false;\r\n};\r\n\r\nclass FilterSection extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const { reportType, startDate, endDate } = this.props.fields;\r\n const {\r\n onInputChange,\r\n onFieldError,\r\n loadRequest,\r\n isProcessing\r\n } = this.props;\r\n const form = formHandler();\r\n return (\r\n \r\n
\r\n \r\n \r\n Filter Reports \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Report Types \r\n validateSelect(\"Report type\", val)}\r\n value={reportType}\r\n onFieldError={onFieldError}\r\n onChange={onInputChange}\r\n >\r\n - Select - ;\r\n {orderBy(reportTypes, [\"order\"], [\"asc\"]).map(\r\n state => {\r\n return (\r\n \r\n {state.label}\r\n \r\n );\r\n }\r\n )}\r\n \r\n \r\n \r\n \r\n \r\n Start Date \r\n \r\n \r\n validators.required(\"Start Date\", val)\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n > \r\n
\r\n \r\n \r\n \r\n \r\n End Date \r\n \r\n \r\n validators.required(\"End Date\", val)\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n > \r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n {\r\n form.validate({\r\n validFn: () => loadRequest(this.props.fields)\r\n });\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Filter\r\n \r\n \r\n \r\n \r\n
\r\n form.validate({\r\n validFn: () => loadRequest(this.props.fields)\r\n })\r\n }\r\n />\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default FilterSection;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport FilterSection from \"./filter-section\";\r\n\r\nclass DownloadReports extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n render() {\r\n return (\r\n <>\r\n \r\n \r\n Download Reports \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default DownloadReports;\r\n","import HttpClient from \"../../../../coreLib//http/httpClient\";\r\nimport moment from \"moment\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const load = payload => {\r\n return httpClient.post(\r\n \"v1/admin/reports/excel\",\r\n {\r\n startDate: moment(payload.startDate),\r\n endDate: moment(payload.endDate),\r\n reportType: payload.reportType\r\n },\r\n {\r\n responseType: \"arraybuffer\"\r\n }\r\n );\r\n };\r\n\r\n return {\r\n load\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"./service\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nexport const loadRequest = params => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_DOWNLOAD_REPORT_REQUEST });\r\n service\r\n .load(params)\r\n .then(resp => {\r\n let file = new Blob([resp.data], {\r\n type:\r\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\r\n });\r\n saveAs(file, \"report.xlsx\");\r\n dispatch(onLoadSuccess());\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n dispatch(addNotification(\"Request failed.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onLoadSuccess = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_DOWNLOAD_REPORT_SUCCESS\r\n });\r\n};\r\n\r\nconst onLoadFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_DOWNLOAD_REPORT_FAILURE\r\n });\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_DOWNLOAD_REPORT_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import DownloadReports from \"./download-reports\";\r\nimport { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => state.adminDownloadReport;\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: error =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n loadRequest: () => {\r\n dispatchProps.dispatch(actionCreators.loadRequest(stateProps.fields));\r\n }\r\n});\r\n\r\nconst DownloadReportsContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n )(DownloadReports)\r\n);\r\n\r\nexport default DownloadReportsContainer;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Modal,\r\n ModalHeader,\r\n ModalBody,\r\n ModalFooter,\r\n Form,\r\n Row,\r\n Col,\r\n FormGroup\r\n} from \"reactstrap\";\r\nimport \"../../../../components/Common/Fields/Fields.scss\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\nimport formHandler from \"../../../../components/Common/Fields/form-handler\";\r\nimport \"../../../../components/Common/Fields/Fields.scss\";\r\nimport InputField from \"../../../../components/Common/Fields/Input-Field\";\r\nimport * as validators from \"../../../../components/Common/Fields/Validators/Field-Validators\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n dialogs,\r\n toggleEditDialog,\r\n onFieldError,\r\n isProcessing,\r\n fields,\r\n onEdit,\r\n onDialogInputChange\r\n } = this.props;\r\n const { companyName, firstName, lastName, email, phone } = fields;\r\n const form = formHandler();\r\n return (\r\n \r\n \r\n toggleEditDialog()}>\r\n Edit Voucher Purchase\r\n \r\n \r\n \r\n \r\n \r\n \r\n Company Name \r\n validators.required(\"Company Name\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n First Name \r\n validators.required(\"First Name\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n \r\n \r\n Last Name \r\n validators.required(\"Last Name\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Email \r\n validators.required(\"Email\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n \r\n \r\n Phone \r\n validators.required(\"Phone\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n
\r\n \r\n \r\n \r\n onEdit(fields)}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Save\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n dialogs,\r\n toggleDeleteDialog,\r\n onDelete,\r\n fields,\r\n isProcessing,\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete Voucher Purchase\r\n \r\n \r\n \r\n Are you sure you want to delete this voucher purchase? Please\r\n note, this will delete the tax invoice and any vouchers attached\r\n to this purchase. This cannot be undone.\r\n \r\n \r\n \r\n onDelete(fields)}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n dialogs,\r\n toggleMarkAsPaidDialog,\r\n onMarkAsPaid,\r\n fields,\r\n isProcessing\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleMarkAsPaidDialog()}>\r\n Mark As Paid\r\n \r\n \r\n \r\n Are you sure you want to mark this purchase as paid? Please note,\r\n this cannot be undone.\r\n \r\n \r\n \r\n onMarkAsPaid(fields.prePurchaseId)}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Save\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter, Table } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class VouchersListDialog extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const { dialogs, vouchers, toggleVouchersDialog } = this.props;\r\n return (\r\n \r\n
\r\n toggleVouchersDialog()}>\r\n Vouchers\r\n \r\n \r\n \r\n \r\n \r\n \r\n Voucher Code \r\n Course \r\n Status \r\n \r\n \r\n \r\n {vouchers.map((voucher, key) => {\r\n return (\r\n \r\n \r\n {voucher.voucherCode} \r\n \r\n {voucher.course} \r\n {voucher.status} \r\n \r\n );\r\n })}\r\n \r\n
\r\n \r\n \r\n \r\n toggleVouchersDialog()}\r\n className=\"ttg-btn\"\r\n isLoading={false}\r\n >\r\n Close\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import SolvableDataTable from \"../../../components/solvable-datatable/solvable-datatable\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport React, { Component } from \"react\";\r\nimport EditDialog from \"./Modals/edit\";\r\nimport DeleteDialog from \"./Modals/delete\";\r\nimport MarkAsPaidDialog from \"./Modals/mark-as-paid\";\r\nimport VouchersDialog from \"./Modals/vouchers-list\";\r\n\r\nclass DataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n settings: {}\r\n };\r\n this.actionButtonHandler = this.actionButtonHandler.bind(this);\r\n }\r\n\r\n columns = [\r\n {\r\n Header: \"Company Name\",\r\n accessor: \"companyName\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Name\",\r\n accessor: \"name\",\r\n searchable: true\r\n },\r\n {\r\n accessor: \"userId\",\r\n show: false\r\n },\r\n {\r\n accessor: \"loginAsUserToken\",\r\n show: false\r\n },\r\n {\r\n accessor: \"prePurchaseId\",\r\n show: false\r\n },\r\n {\r\n accessor: \"vouchers\",\r\n show: false\r\n },\r\n {\r\n accessor: \"invoiceGuid\",\r\n show: false\r\n },\r\n {\r\n Header: \"Email\",\r\n accessor: \"email\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Phone\",\r\n accessor: \"phone\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Amount Due\",\r\n accessor: \"amountDue\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Amount Paid\",\r\n accessor: \"amountPaid\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Discount\",\r\n accessor: \"discountAmount\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Credit Card Purchase\",\r\n accessor: \"isCreditCardPurchase\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Purchased Date\",\r\n accessor: \"purchasedDateTime\",\r\n searchable: true\r\n }\r\n ];\r\n\r\n actionButtonHandler = evt => {\r\n const {\r\n toggleEditDialog,\r\n downloadTaxInvoice,\r\n toggleDeleteDialog,\r\n toggleVouchersDialog,\r\n toggleMarkAsPaidDialog\r\n } = this.props;\r\n switch (evt.type) {\r\n case \"button1\":\r\n toggleEditDialog(evt.data);\r\n break;\r\n case \"button2\":\r\n toggleMarkAsPaidDialog(evt.data);\r\n break;\r\n case \"button3\":\r\n toggleDeleteDialog(evt.data);\r\n break;\r\n case \"button4\":\r\n toggleVouchersDialog(evt.data.vouchers);\r\n break;\r\n case \"button5\":\r\n downloadTaxInvoice(evt.data.invoiceGuid);\r\n break;\r\n }\r\n };\r\n\r\n render() {\r\n const { data, isProcessing, settings } = this.props.dataTable;\r\n const {\r\n toggleDeleteDialog,\r\n toggleVouchersDialog,\r\n toggleEditDialog,\r\n toggleMarkAsPaidDialog,\r\n onFieldError,\r\n onEdit,\r\n onMarkAsPaid,\r\n onDelete,\r\n onSettingsChanged,\r\n onDialogInputChange\r\n } = this.props;\r\n const {\r\n isProcessing: isDialogProcessing,\r\n dialogs,\r\n fields,\r\n vouchers\r\n } = this.props.dialog;\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n row.amountPaid !== \"$0.00\",\r\n tooltip: \"Mark as paid\",\r\n },\r\n {\r\n target: \"button3\",\r\n icon: \"fas fa-trash-alt\",\r\n tooltip: \"Delete voucher\",\r\n },\r\n {\r\n target: \"button4\",\r\n icon: \"fas fa-list-alt\",\r\n tooltip: \"View vouchers\",\r\n },\r\n {\r\n target: \"button5\",\r\n icon: \"fas fa-download\",\r\n tooltip: \"Download tax invoice\",\r\n hideFn: (row) => row.invoiceGuid === null,\r\n },\r\n {\r\n target: \"button6\",\r\n icon: \"fas fa-address-card\",\r\n tooltip:\r\n \"You can right click “Open link in incognito window” to avoid having to log out and in again\",\r\n to: (row) => {\r\n return `/login/${row.userId}/${row.loginAsUserToken}`;\r\n },\r\n },\r\n ],\r\n }}\r\n keepSettings={true}\r\n stateSettings={settings}\r\n onSettingsChanged={onSettingsChanged}\r\n onActionButtonClick={this.actionButtonHandler}\r\n data={data}\r\n />\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default DataTable;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Card,\r\n CardBody,\r\n CardFooter,\r\n CardHeader,\r\n Input,\r\n Row,\r\n Col,\r\n Collapse,\r\n Form,\r\n FormGroup\r\n} from \"reactstrap\";\r\nimport {} from \"../../../constants\";\r\nimport ReactSelectField from \"../../../components/Common/Fields/React-Select-Field\";\r\nimport DatePickerField from \"../../../components/Common/Fields/Date-Picker-Field\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport * as validators from \"../../../components/Common/Fields/Validators/Field-Validators\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport CourseService from \"../../../services/course-service\";\r\n\r\nclass FilterSection extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n showFilters: false\r\n };\r\n }\r\n\r\n toggle = () => {\r\n this.setState({\r\n showFilters: !this.state.showFilters\r\n });\r\n };\r\n\r\n render() {\r\n const { showFilters } = this.state;\r\n const form = formHandler();\r\n const {\r\n dataTable,\r\n onInputChange,\r\n onFieldError,\r\n onLoad,\r\n reset\r\n } = this.props;\r\n const { isProcessing } = dataTable;\r\n const { courseIds, startDate, endDate } = dataTable.fields;\r\n\r\n const courses = CourseService()\r\n .getCourses()\r\n .map(course => {\r\n return {\r\n label: course.courseTitle,\r\n value: course.courseId\r\n };\r\n });\r\n return (\r\n \r\n
\r\n \r\n \r\n Filter Vouchers \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Courses \r\n validators.required(\"Course\", val)}\r\n showSelectAll={true}\r\n selectAllByDefault={true}\r\n ref={form.add}\r\n onChange={onInputChange}\r\n onFieldError={onFieldError}\r\n keepSettings={true}\r\n options={courses}\r\n value={courseIds}\r\n />\r\n \r\n \r\n \r\n \r\n Start Date \r\n \r\n \r\n validators.required(\"Start Date\", val)\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n > \r\n
\r\n \r\n \r\n \r\n \r\n End Date \r\n \r\n \r\n validators.required(\"End Date\", val)\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n > \r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n form.validate({\r\n validFn: () => onLoad(dataTable.fields)\r\n })\r\n }\r\n type=\"submit\"\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Filter\r\n \r\n reset()}\r\n className=\"ttg-blue-btn ml-2\"\r\n isLoading={isProcessing}\r\n >\r\n Reset\r\n \r\n \r\n \r\n \r\n form.validate({\r\n validFn: () => onLoad(dataTable.fields)\r\n })\r\n }\r\n />\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default FilterSection;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport Datatable from \"./datatable\";\r\nimport FilterSection from \"./filter-section\";\r\nimport ToggleDisplay from \"react-toggle-display\";\r\n\r\nclass VoucherPurchases extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoad } = this.props;\r\n onLoad();\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n const { isProcessing, isReset } = this.props.dataTable;\r\n return (\r\n <>\r\n \r\n \r\n Voucher Purchases \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default VoucherPurchases;\r\n","import HttpClient from \"../../../../coreLib//http/httpClient\";\r\nimport moment from \"moment\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const loadVouchers = payload => {\r\n let model = {\r\n courseIds: payload.courseIds.map(course =>\r\n typeof course === \"object\" ? course.value : course\r\n ),\r\n startDate: moment(payload.startDate),\r\n endDate: moment(payload.endDate)\r\n };\r\n return httpClient.post(\"v1/admin/vouchers\", model);\r\n };\r\n\r\n const updateVouchers = payload => {\r\n let model = {\r\n companyName: payload.companyName,\r\n firstName: payload.firstName,\r\n lastName: payload.lastName,\r\n email: payload.email,\r\n phone: payload.phone\r\n };\r\n return httpClient.put(`v1/admin/vouchers/${payload.prePurchaseId}`, model);\r\n };\r\n\r\n const deleteVoucher = payload => {\r\n return httpClient.delete(`v1/admin/vouchers/${payload.prePurchaseId}`);\r\n };\r\n\r\n const markAsPaid = prePurchaseId => {\r\n return httpClient.put(`v1/admin/vouchers/${prePurchaseId}/paid`, {\r\n isPaid: true\r\n });\r\n };\r\n\r\n const downloadTaxInvoice = invoiceId => {\r\n return httpClient.get(`v1/userCourse/pdf/tax-invoice/${invoiceId}`, {\r\n responseType: \"blob\"\r\n });\r\n };\r\n\r\n return {\r\n loadVouchers,\r\n updateVouchers,\r\n deleteVoucher,\r\n markAsPaid,\r\n downloadTaxInvoice\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\nimport CourseService from \"../../../../../services/course-service\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport moment from \"moment\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nexport const onLoad = () => (dispatch, getState) => {\r\n let fieldValues = getState().adminVouchers.DataTable.fields;\r\n let params = fieldValues ? fieldValues : getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const resetData = () => dispatch => {\r\n let params = getInitialParams();\r\n dispatch(loadRequest(params));\r\n};\r\n\r\nexport const loadRequest = params => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_ONLOAD_REQUEST });\r\n service\r\n .loadVouchers(params)\r\n .then(resp => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n dispatch(addNotification(\"Unable to load vouchers.\", \"warning\"));\r\n });\r\n};\r\n\r\nexport const reset = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_RESET });\r\n dispatch(resetData());\r\n};\r\n\r\nconst onLoadFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_ONLOAD_FAILURE\r\n });\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n\r\nconst getInitialParams = () => {\r\n return {\r\n courseIds: CourseService()\r\n .getCourses()\r\n .map(course => course.courseId),\r\n startDate: moment().subtract(12, \"months\")._d,\r\n endDate: moment()._d\r\n };\r\n};\r\n\r\nconst onLoadSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_ONLOAD_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nexport const downloadTaxInvoice = invoidGuid => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DOWNLOAD_TAX_INVOICE_REQUEST\r\n });\r\n let service = HttpService();\r\n service\r\n .downloadTaxInvoice(invoidGuid)\r\n .then(resp => {\r\n dispatch(onDownloadTaxInvoiceSuccess());\r\n const pdfBlob = new Blob([resp.data], { type: \"application/pdf\" });\r\n saveAs(pdfBlob, \"taxinvoice.pdf\");\r\n })\r\n .catch(() => {\r\n dispatch(onDownloadTaxInvoiceFailure());\r\n dispatch(addNotification(\"Unable to download tax invoice.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onDownloadTaxInvoiceSuccess = () => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DOWNLOAD_TAX_INVOICE_SUCCESS\r\n});\r\n\r\nconst onDownloadTaxInvoiceFailure = () => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DOWNLOAD_TAX_INVOICE_FAILURE\r\n});\r\n\r\nexport const keepDataTableSettings = settings => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings\r\n }\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DATATABLE_CLEAR_SEARCHBOX,\r\n});\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\n\r\nexport const toggleDeleteDialog = payload => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_SHOW_DELETE_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleEditDialog = payload => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_SHOW_EDIT_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleVouchersDialog = payload => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_SHOW_VOUCHERS_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleMarkAsPaidDialog = payload => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_SHOW_MARK_AS_PAID_DIALOG,\r\n payload\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DIALOG_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n\r\nexport const updateVoucher = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_UPDATE_REQUEST });\r\n service\r\n .updateVouchers(payload)\r\n .then(() => {\r\n dispatch(updateVoucherSuccess(payload));\r\n dispatch(addNotification(\"Voucher has been updated.\"));\r\n })\r\n .catch(() => {\r\n dispatch(updateVoucherFailure());\r\n dispatch(addNotification(\"Unable to update the voucher.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst updateVoucherSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_UPDATE_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst updateVoucherFailure = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_UPDATE_FAILURE });\r\n};\r\n\r\nexport const deleteVoucher = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DELETE_REQUEST });\r\n service\r\n .deleteVoucher(payload)\r\n .then(() => {\r\n dispatch(deleteVoucherSuccess(payload));\r\n dispatch(addNotification(\"Voucher has been deleted.\"));\r\n })\r\n .catch(() => {\r\n dispatch(deleteVoucherFailure());\r\n dispatch(addNotification(\"Unable to delete the voucher.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst deleteVoucherSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DELETE_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst deleteVoucherFailure = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_DELETE_FAILURE });\r\n};\r\n\r\nexport const markAsPaid = prePurchaseId => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_PAID_REQUEST });\r\n service\r\n .markAsPaid(prePurchaseId)\r\n .then(() => {\r\n dispatch(markAsPaidSuccess(prePurchaseId));\r\n dispatch(addNotification(\"Successfully mark as paid.\"));\r\n })\r\n .catch(() => {\r\n dispatch(markAsPaidFailure());\r\n dispatch(addNotification(\"Unable to mark as paid\", \"warning\"));\r\n });\r\n};\r\n\r\nconst markAsPaidSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_PAID_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst markAsPaidFailure = () => dispatch => {\r\n dispatch({ type: ActionTypes.ADMIN_PURCHASE_VOUCHERS_PAID_FAILURE });\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport VoucherPurchases from \"./voucher-purchases\";\r\nimport * as dataTableActionCreators from \"./redux/datatable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.adminVouchers.DataTable,\r\n dialog: state.adminVouchers.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoad: (payload) => dispatch(dataTableActionCreators.onLoad(payload)),\r\n reset: () => dispatch(dataTableActionCreators.reset()),\r\n toggleEditDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleEditDialog(payload)),\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(dataTableActionCreators.formInputChange(name, value, error));\r\n },\r\n onEdit: (payload) => dispatch(dialogActionCreators.updateVoucher(payload)),\r\n onDelete: (payload) => dispatch(dialogActionCreators.deleteVoucher(payload)),\r\n onMarkAsPaid: (payload) => dispatch(dialogActionCreators.markAsPaid(payload)),\r\n onDialogInputChange: ({ name, value, error }) => {\r\n dispatch(dialogActionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n toggleDeleteDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleDeleteDialog(payload)),\r\n toggleMarkAsPaidDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleMarkAsPaidDialog(payload)),\r\n toggleVouchersDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleVouchersDialog(payload)),\r\n downloadTaxInvoice: (invoiceGuid) =>\r\n dispatch(dataTableActionCreators.downloadTaxInvoice(invoiceGuid)),\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst VoucherPurchasesContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n )(VoucherPurchases)\r\n);\r\n\r\nexport default VoucherPurchasesContainer;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Input,\r\n Form,\r\n FormGroup,\r\n Row,\r\n Col,\r\n Label,\r\n Modal,\r\n ModalHeader,\r\n ModalBody,\r\n ModalFooter,\r\n} from \"reactstrap\";\r\nimport \"react-datepicker/dist/react-datepicker.css\";\r\nimport formHandler from \"../../../../components/Common/Fields/form-handler\";\r\nimport InputField from \"../../../../components/Common/Fields/Input-Field\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\nimport DatePickerField from \"../../../../components/Common/Fields/Date-Picker-Field\";\r\nimport SelectField from \"../../../../components/Common/Fields/Select-Field\";\r\n\r\nclass ViewDetailsNswReprints extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const { isModalOpen, fields, isModalLoading } = this.props.dialog;\r\n const { onToggle, onDialogInputChange, onFieldError, update } = this.props;\r\n const form = formHandler();\r\n\r\n return (\r\n \r\n onToggle()}>\r\n NSW Certificate Details\r\n \r\n \r\n \r\n \r\n \r\n \r\n First Name \r\n \r\n \r\n \r\n \r\n \r\n Last Name \r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Email \r\n \r\n \r\n \r\n \r\n \r\n Phone \r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Certificate Number \r\n \r\n \r\n \r\n \r\n \r\n Certificate Date/Time \r\n \r\n \r\n \r\n
\r\n\r\n \r\n Postal Address \r\n \r\n \r\n\r\n \r\n \r\n \r\n Edit these details\r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n NSW Certificate Number \r\n \r\n \r\n \r\n \r\n \r\n Express Post Number \r\n \r\n \r\n \r\n
\r\n \r\n Date Sent \r\n \r\n \r\n
\r\n \r\n\r\n \r\n Status \r\n \r\n - Select - \r\n Unactioned \r\n Underway \r\n Completed \r\n \r\n \r\n \r\n \r\n \r\n {\r\n form.validate({\r\n validFn: () => {\r\n update(fields);\r\n },\r\n });\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isModalLoading}\r\n >\r\n Update\r\n \r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nexport default ViewDetailsNswReprints;\r\n","import React, { Component } from \"react\";\r\nimport BlockUiFx from \"./../../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport SolvableDataTable from \"./../../../../components/solvable-datatable/solvable-datatable\";\r\nimport ViewDetailsNswCertificate from \"./../Modals/View-Details\";\r\n\r\nclass NswReprintsDataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.columns = this.setupDataTable();\r\n }\r\n\r\n setupDataTable = () => {\r\n return [\r\n {\r\n Header: \"First Name\",\r\n accessor: \"firstName\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Last Name\",\r\n accessor: \"lastName\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Email\",\r\n accessor: \"email\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Phone\",\r\n accessor: \"phone\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Certificate Number\",\r\n accessor: \"certificateNumber\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Certificate Date/Time\",\r\n accessor: \"certificateDateTime\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Status\",\r\n accessor: \"status\",\r\n searchable: true\r\n }\r\n ];\r\n };\r\n\r\n render() {\r\n const { isLoading, data, settings } = this.props.dataTable;\r\n const {\r\n handleError,\r\n onSettingsChanged,\r\n onActionButtonHandler\r\n } = this.props;\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default NswReprintsDataTable;\r\n","import React, { Component } from \"react\";\r\nimport NswCertDataTable from \"./Data-Table/Data-Table\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section/index\";\r\n\r\nexport default class NswCertificatesViewContainer extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoadData } = this.props;\r\n onLoadData();\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n const { data } = this.props.dataTable;\r\n const { actionButtonHandler } = this.props;\r\n return (\r\n <>\r\n \r\n \r\n NSW Certificates \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n","import HttpClient from \"../../../coreLib/http/httpClient\";\r\nimport DateService from \"../../../services/date-service\";\r\n\r\nconst NswReprintsService = () => {\r\n let httpClient = HttpClient();\r\n let dateService = DateService();\r\n\r\n const loadData = () => {\r\n return httpClient.get(\"/v1/admin/nsw/certificates\");\r\n };\r\n\r\n const update = payload => {\r\n return httpClient.put(\r\n `/v1/admin/nsw/certificates/${payload.userCourseId}`,\r\n {\r\n nswCertificateNumber: payload.nswCertificateNumber,\r\n expressPostNumber: payload.expressPostNumber,\r\n dateSent: dateService.toIsoDate(payload.dateSent),\r\n status: payload.status\r\n }\r\n );\r\n };\r\n\r\n return {\r\n loadData,\r\n update\r\n };\r\n};\r\n\r\nexport default NswReprintsService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport NswReprintsService from \"../../service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const loadData = () => {\r\n return dispatch => {\r\n dispatch(loadDataRequest());\r\n const service = NswReprintsService();\r\n\r\n service\r\n .loadData()\r\n .then(resp => {\r\n dispatch(loadDataSuccess(resp.data));\r\n })\r\n .catch(err => {\r\n dispatch(loadDataFailure(err));\r\n dispatch(\r\n addNotification(\"Unable to load data for this page.\", \"error\")\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst loadDataRequest = () => ({\r\n type: ActionTypes.NSW_CERTIFICATES_LOAD_DATA_REQUEST\r\n});\r\n\r\nconst loadDataSuccess = payload => ({\r\n type: ActionTypes.NSW_CERTIFICATES_LOAD_DATA_SUCCESS,\r\n payload\r\n});\r\n\r\nconst loadDataFailure = err => ({\r\n type: ActionTypes.NSW_CERTIFICATES_LOAD_DATA_FAILURE,\r\n payload: err\r\n});\r\n\r\nexport const keepDataTableSettings = settings => ({\r\n type: ActionTypes.NSW_CERTIFICATES_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings\r\n }\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.NSW_CERTIFICATES_DATATABLE_CLEAR_SEARCHBOX,\r\n});\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport NswReprintsService from \"../../service\";\r\n\r\nexport const toggleDialog = payload => dispatch => {\r\n dispatch({ type: ActionTypes.NSW_CERTIFICATES_VIEW_TOGGLE_DIALOG, payload });\r\n};\r\n\r\nexport const update = payload => dispatch => {\r\n let service = NswReprintsService();\r\n dispatch({ type: ActionTypes.NSW_CERTIFICATES_VIEW_UPDATE_REQUEST });\r\n service\r\n .update(payload)\r\n .then(() => {\r\n dispatch(updateSuccess(payload));\r\n dispatch(addNotification(\"Successfully updated.\"));\r\n })\r\n .catch(() => {\r\n dispatch(updateFailure());\r\n dispatch(addNotification(\"Unable to update.\", \"error\"));\r\n });\r\n};\r\n\r\nconst updateSuccess = payload => ({\r\n type: ActionTypes.NSW_CERTIFICATES_VIEW_UPDATE_SUCCESS,\r\n payload\r\n});\r\n\r\nconst updateFailure = () => ({\r\n type: ActionTypes.NSW_CERTIFICATES_VIEW_UPDATE_FAILURE\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.NSW_CERTIFICATES_VIEW_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import NswCertificates from \"./Nsw-Certificates\";\r\nimport { connect } from \"react-redux\";\r\nimport * as dataTableActionCreators from \"./redux/dataTable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.nswCertificates.DataTable,\r\n dialog: state.nswCertificates.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoadData: () => {\r\n dispatch(dataTableActionCreators.loadData());\r\n },\r\n actionButtonHandler: (evt) => {\r\n if (evt.type === \"button1\") {\r\n dispatch(dialogActionCreators.toggleDialog(evt.data));\r\n }\r\n },\r\n onDialogInputChange: ({ name, value, error }) => {\r\n dispatch(dialogActionCreators.formInputChange(name, value, error));\r\n },\r\n update: (payload) => {\r\n dispatch(dialogActionCreators.update(payload));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n onToggle: (payload) => {\r\n dispatch(dialogActionCreators.toggleDialog(payload));\r\n },\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nexport default withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n )(NswCertificates)\r\n);\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Input,\r\n Form,\r\n FormGroup,\r\n Row,\r\n Col,\r\n Label,\r\n Modal,\r\n ModalHeader,\r\n ModalBody,\r\n ModalFooter\r\n} from \"reactstrap\";\r\nimport \"react-datepicker/dist/react-datepicker.css\";\r\nimport formHandler from \"../../../../components/Common/Fields/form-handler\";\r\nimport InputField from \"../../../../components/Common/Fields/Input-Field\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\nimport DatePickerField from \"../../../../components/Common/Fields/Date-Picker-Field\";\r\nimport SelectField from \"../../../../components/Common/Fields/Select-Field\";\r\nimport * as validators from \"../../../../components/Common/Fields/Validators/Field-Validators\";\r\n\r\nconst validateSelect = (fieldName, value) => {\r\n if (validators.required(fieldName, value) || value === \"-1\") {\r\n return `${fieldName} is required.`;\r\n }\r\n return false;\r\n};\r\n\r\nclass ViewDetailsNswReprints extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const { isModalOpen, fields, isModalLoading } = this.props.dialog;\r\n const { onToggle, onDialogInputChange, onFieldError, update } = this.props;\r\n const form = formHandler();\r\n\r\n return (\r\n \r\n onToggle()}>NSW Reprint Details \r\n \r\n \r\n \r\n \r\n \r\n First Name \r\n \r\n \r\n \r\n \r\n \r\n Last Name \r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Email \r\n \r\n \r\n \r\n \r\n \r\n Phone \r\n \r\n \r\n \r\n
\r\n\r\n \r\n Postal Address \r\n \r\n \r\n\r\n \r\n \r\n View Original Certificate{\" \"}\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n NSW Certificate Number \r\n \r\n \r\n \r\n \r\n \r\n Express Post Number \r\n \r\n \r\n \r\n
\r\n\r\n \r\n Date Sent \r\n \r\n \r\n
\r\n \r\n\r\n \r\n Status \r\n \r\n - Select - \r\n Unactioned \r\n Underway \r\n Completed \r\n \r\n \r\n \r\n \r\n \r\n {\r\n form.validate({\r\n validFn: () => {\r\n update(fields);\r\n }\r\n });\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isModalLoading}\r\n >\r\n Update\r\n \r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nexport default ViewDetailsNswReprints;\r\n","/**\r\n * NSW Reprints Data table\r\n */\r\nimport React, { Component } from \"react\";\r\nimport BlockUiFx from \"./../../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport SolvableDataTable from \"./../../../../components/solvable-datatable/solvable-datatable\";\r\nimport ViewDetailsNswCertificate from \"./../Modals/View-Details\";\r\nimport \"../nsw-reprint.scss\";\r\n\r\nclass NswReprintsDataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.columns = this.setupDataTable();\r\n }\r\n\r\n setupDataTable = () => {\r\n return [\r\n {\r\n Header: \"First Name\",\r\n accessor: \"firstName\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Last Name\",\r\n accessor: \"lastName\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Email\",\r\n accessor: \"email\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Phone\",\r\n accessor: \"phone\",\r\n searchable: true\r\n },\r\n {\r\n Header: \"Purchased Date/Time\",\r\n accessor: \"purchasedDateTime\",\r\n searchable: true,\r\n width: 200\r\n },\r\n {\r\n Header: \"Status\",\r\n accessor: \"status\",\r\n searchable: true\r\n }\r\n ];\r\n };\r\n\r\n render() {\r\n const { isLoading, data, settings } = this.props.dataTable;\r\n const {\r\n handleError,\r\n onSettingsChanged,\r\n onActionButtonHandler\r\n } = this.props;\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default NswReprintsDataTable;\r\n","import React, { Component } from \"react\";\r\nimport \"./nsw-reprint.scss\";\r\nimport NswCertDataTable from \"./Data-Table/Data-Table\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section/index\";\r\n\r\nexport default class NswReprintsViewContainer extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoadData } = this.props;\r\n onLoadData();\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n const { data } = this.props.dataTable;\r\n const { actionButtonHandler } = this.props;\r\n return (\r\n <>\r\n \r\n \r\n View NSW Reprints \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n","import HttpClient from \"../../../coreLib/http/httpClient\";\r\nimport DateService from \"../../../services/date-service\";\r\n\r\nconst NswReprintsService = () => {\r\n let httpClient = HttpClient();\r\n let dateService = DateService();\r\n\r\n const loadData = () => {\r\n return httpClient.get(\"/v1/admin/nsw/reprints\");\r\n };\r\n\r\n const update = payload => {\r\n return httpClient.put(`/v1/admin/nsw/reprints/${payload.id}`, {\r\n nswCertificateNumber: payload.nswCertificateNumber,\r\n expressPostNumber: payload.expressPostNumber,\r\n dateSent: dateService.toIsoDate(payload.dateSent),\r\n status: payload.status\r\n });\r\n };\r\n\r\n return {\r\n loadData,\r\n update\r\n };\r\n};\r\n\r\nexport default NswReprintsService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport NswReprintsService from \"../../service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const loadData = () => {\r\n return dispatch => {\r\n dispatch(loadDataRequest());\r\n const service = NswReprintsService();\r\n\r\n service\r\n .loadData()\r\n .then(resp => {\r\n dispatch(loadDataSuccess(resp.data));\r\n })\r\n .catch(err => {\r\n dispatch(loadDataFailure(err));\r\n dispatch(\r\n addNotification(\"Unable to load data for this page.\", \"error\")\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst loadDataRequest = () => ({\r\n type: ActionTypes.NSW_REPRINTS_LOAD_DATA_REQUEST\r\n});\r\n\r\nconst loadDataSuccess = payload => ({\r\n type: ActionTypes.NSW_REPRINTS_LOAD_DATA_SUCCESS,\r\n payload: payload\r\n});\r\n\r\nconst loadDataFailure = err => ({\r\n type: ActionTypes.NSW_REPRINTS_LOAD_DATA_FAILURE,\r\n payload: err\r\n});\r\n\r\nexport const keepDataTableSettings = settings => ({\r\n type: ActionTypes.NSW_REPRINTS_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings\r\n }\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.NSW_REPRINTS_DATATABLE_CLEAR_SEARCHBOX,\r\n});\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport NswReprintsService from \"../../service\";\r\n\r\nexport const toggleDialog = payload => dispatch => {\r\n dispatch({ type: ActionTypes.NSW_REPRINTS_VIEW_TOGGLE_DIALOG, payload });\r\n};\r\n\r\nexport const update = payload => dispatch => {\r\n let service = NswReprintsService();\r\n dispatch({ type: ActionTypes.NSW_REPRINTS_VIEW_UPDATE_REQUEST });\r\n service\r\n .update(payload)\r\n .then(() => {\r\n dispatch(updateSuccess(payload));\r\n dispatch(addNotification(\"Successfully updated.\"));\r\n })\r\n .catch(() => {\r\n dispatch(updateFailure());\r\n dispatch(addNotification(\"Unable to update.\", \"error\"));\r\n });\r\n};\r\n\r\nconst updateSuccess = payload => ({\r\n type: ActionTypes.NSW_REPRINTS_VIEW_UPDATE_SUCCESS,\r\n payload\r\n});\r\n\r\nconst updateFailure = () => ({\r\n type: ActionTypes.NSW_REPRINTS_VIEW_UPDATE_FAILURE\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.NSW_REPRINTS_VIEW_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import NswReprints from \"./Nsw-Reprints-View\";\r\nimport { connect } from \"react-redux\";\r\nimport \"./nsw-reprint.scss\";\r\nimport * as dataTableActionCreators from \"./redux/dataTable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.nswReprintsView.DataTable,\r\n dialog: state.nswReprintsView.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoadData: () => {\r\n dispatch(dataTableActionCreators.loadData());\r\n },\r\n actionButtonHandler: (evt) => {\r\n if (evt.type === \"button1\") {\r\n dispatch(dialogActionCreators.toggleDialog(evt.data));\r\n }\r\n },\r\n onDialogInputChange: ({ name, value, error }) => {\r\n dispatch(dialogActionCreators.formInputChange(name, value, error));\r\n },\r\n update: (payload) => {\r\n dispatch(dialogActionCreators.update(payload));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n onToggle: (payload) => {\r\n dispatch(dialogActionCreators.toggleDialog(payload));\r\n },\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst NswReprintsViewContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n )(NswReprints)\r\n);\r\n\r\nexport default NswReprintsViewContainer;\r\n","import React, { Component } from \"react\";\r\nimport {\r\n Modal,\r\n ModalHeader,\r\n ModalBody,\r\n ModalFooter,\r\n Form,\r\n Row,\r\n Col,\r\n FormGroup\r\n} from \"reactstrap\";\r\nimport formHandler from \"../../../../components/Common/Fields/form-handler\";\r\nimport \"../../../../components/Common/Fields/Fields.scss\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\nimport InputField from \"../../../../components/Common/Fields/Input-Field\";\r\nimport SelectField from \"../../../../components/Common/Fields/Select-Field\";\r\nimport DatePickerField from \"../../../../components/Common/Fields/Date-Picker-Field\";\r\nimport * as validators from \"../../../../components/Common/Fields/Validators/Field-Validators\";\r\n\r\nconst validateSelect = (fieldName, value) => {\r\n if (validators.required(fieldName, value) || value === \"-1\") {\r\n return `${fieldName} is required.`;\r\n }\r\n return false;\r\n};\r\n\r\nexport default class EntryModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n toggleEditDialog,\r\n onFieldError,\r\n onDialogInputChange,\r\n onEdit,\r\n onAdd,\r\n dialogs,\r\n isProcessing,\r\n isEdit,\r\n fields\r\n } = this.props;\r\n const {\r\n discountCode,\r\n discountPercentage,\r\n discountAmount,\r\n expiryDate,\r\n isOneUseOnly\r\n } = fields;\r\n const form = formHandler();\r\n return (\r\n \r\n
\r\n toggleEditDialog()}>\r\n {`${isEdit ? \"Edit\" : \"Add\"} Promo Code`}\r\n \r\n \r\n \r\n \r\n \r\n \r\n Promo Code \r\n validators.required(\"Promo Code\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Discount % \r\n validators.required(\"Discount %\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n \r\n \r\n Discount $ \r\n validators.required(\"Discount $\", val)}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n />\r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n Expires On \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n One Time Use \r\n validateSelect(\"One Time Use\", val)}\r\n value={isOneUseOnly}\r\n onFieldError={onFieldError}\r\n onChange={onDialogInputChange}\r\n >\r\n - Select - \r\n Yes ;\r\n No ;\r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n form.validate({\r\n validFn: () => {\r\n isEdit ? onEdit(fields) : onAdd(fields);\r\n }\r\n })\r\n }\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Save\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class DeleteModal extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n dialogs,\r\n toggleDeleteDialog,\r\n fields,\r\n onDelete,\r\n isProcessing\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete Promo Code\r\n \r\n \r\n \r\n Are you sure you want to delete this promo code? Please note, this\r\n cannot be undone.\r\n \r\n \r\n \r\n {\r\n onDelete(fields);\r\n }}\r\n className=\"ttg-btn\"\r\n isLoading={isProcessing}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import SolvableDataTable from \"../../../components/solvable-datatable/solvable-datatable\";\r\nimport BlockUiFx from \"../../../components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport React, { Component } from \"react\";\r\nimport EditDialog from \"./Modals/edit\";\r\nimport DeleteDialog from \"./Modals/delete\";\r\n\r\nclass DataTable extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n settings: {}\r\n };\r\n this.actionButtonHandler = this.actionButtonHandler.bind(this);\r\n }\r\n\r\n onSettingsChanged = settings => {\r\n this.setState({ settings });\r\n };\r\n\r\n columns = [\r\n {\r\n accessor: \"id\",\r\n show: false\r\n },\r\n {\r\n Header: \"Promo Code\",\r\n accessor: \"discountCode\",\r\n searchable: true\r\n },\r\n {\r\n accessor: \"discountPercentage\",\r\n show: false\r\n },\r\n {\r\n Header: \"Discount %\",\r\n accessor: \"discountPercentage2\",\r\n searchable: true\r\n },\r\n {\r\n accessor: \"discountAmount\",\r\n show: false\r\n },\r\n {\r\n Header: \"Discount $\",\r\n accessor: \"discountAmount2\",\r\n searchable: true\r\n },\r\n\r\n {\r\n accessor: \"expiryDate\",\r\n show: false\r\n },\r\n {\r\n Header: \"Expires On\",\r\n accessor: \"expiryDate2\",\r\n searchable: true\r\n },\r\n {\r\n accessor: \"isOneUseOnly\",\r\n show: false\r\n },\r\n {\r\n Header: \"One Time Use\",\r\n accessor: \"isOneUseOnly2\",\r\n searchable: true\r\n }\r\n ];\r\n\r\n actionButtonHandler = evt => {\r\n const {\r\n toggleEditDialog,\r\n toggleDeleteDialog,\r\n toggleAddDialog\r\n } = this.props;\r\n switch (evt.type) {\r\n case \"button1\":\r\n toggleAddDialog();\r\n break;\r\n case \"button2\":\r\n toggleEditDialog(evt.data);\r\n break;\r\n case \"button3\":\r\n toggleDeleteDialog(evt.data);\r\n break;\r\n }\r\n };\r\n\r\n render() {\r\n const {\r\n toggleEditDialog,\r\n toggleDeleteDialog,\r\n onFieldError,\r\n onDelete,\r\n onEdit,\r\n onAdd,\r\n dataTable,\r\n dialog,\r\n onSettingsChanged,\r\n onDialogInputChange\r\n } = this.props;\r\n const { data, isProcessing, settings } = dataTable;\r\n const {\r\n dialogs,\r\n fields,\r\n isProcessing: isDialogProcessing,\r\n isEdit\r\n } = dialog;\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default DataTable;\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport Datatable from \"./datatable\";\r\n\r\nclass Users extends Component {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n componentDidMount() {\r\n const { onLoad } = this.props;\r\n onLoad();\r\n this.props.clearDataTableSearchbox();\r\n }\r\n\r\n render() {\r\n return (\r\n <>\r\n \r\n \r\n Promo Codes \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default Users;\r\n","import HttpClient from \"../../../../coreLib//http/httpClient\";\r\n\r\nconst Service = () => {\r\n let httpClient = HttpClient();\r\n\r\n const load = () => {\r\n return httpClient.get(\"v1/admin/promocodes\");\r\n };\r\n\r\n const deletePromoCode = id => {\r\n return httpClient.delete(`v1/admin/promocodes/${id}`);\r\n };\r\n\r\n const addPromoCode = payload => {\r\n let model = {\r\n discountCode: payload.discountCode,\r\n discountPercentage: payload.discountPercentage / 100,\r\n discountAmount: payload.discountAmount,\r\n expiryDate: payload.expiryDate,\r\n isOneUseOnly: payload.isOneUseOnly\r\n };\r\n return httpClient.post(`v1/admin/promocodes/`, model);\r\n };\r\n\r\n const editPromoCode = payload => {\r\n let model = {\r\n discountCode: payload.discountCode,\r\n discountPercentage: payload.discountPercentage / 100,\r\n discountAmount: payload.discountAmount,\r\n expiryDate: payload.expiryDate,\r\n isOneUseOnly:\r\n payload.isOneUseOnly === true || payload.isOneUseOnly === \"true\"\r\n ? true\r\n : false\r\n };\r\n return httpClient.put(`v1/admin/promocodes/${payload.id}`, model);\r\n };\r\n\r\n return {\r\n load,\r\n deletePromoCode,\r\n addPromoCode,\r\n editPromoCode\r\n };\r\n};\r\n\r\nexport default Service;\r\n","import { ActionTypes } from \"./action-types\";\r\nimport HttpService from \"../service\";\r\n\r\nexport const onLoad = () => dispatch => {\r\n dispatch(loadRequest());\r\n};\r\n\r\nexport const loadRequest = params => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PROMO_CODES_ONLOAD_REQUEST });\r\n service\r\n .load(params)\r\n .then(resp => {\r\n dispatch(onLoadSuccess(resp.data));\r\n })\r\n .catch(() => {\r\n dispatch(onLoadFailure());\r\n });\r\n};\r\n\r\nconst onLoadSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_ONLOAD_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onLoadFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_ONLOAD_FAILURE\r\n });\r\n};\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_FILTER_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n\r\nexport const keepDataTableSettings = settings => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_DATATABLE_KEEP_SETTINGS,\r\n payload: {\r\n settings\r\n }\r\n});\r\n\r\nexport const clearDataTableSearchboxFilter = () => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_DATATABLE_CLEAR_SEARCHBOX,\r\n});\r\n","import { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../../redux/system/system-action-creators\";\r\nimport HttpService from \"../service\";\r\n\r\nexport const onDelete = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PROMO_CODES_DELETE_REQUEST });\r\n service\r\n .deletePromoCode(payload.id)\r\n .then(() => {\r\n dispatch(onDeleteSuccess(payload));\r\n dispatch(addNotification(\"Promo code has been successfully deleted.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onDeleteFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an error deleting the promo code.\",\r\n \"warning\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nconst onDeleteSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_DELETE_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nexport const onAdd = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PROMO_CODES_ADD_REQUEST });\r\n service\r\n .addPromoCode(payload)\r\n .then(() => {\r\n dispatch(onAddSuccess(payload));\r\n dispatch(addNotification(\"Promo code has been successfully added.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onAddFailure());\r\n dispatch(addNotification(\"Unable to add a promo code.\", \"warning\"));\r\n });\r\n};\r\n\r\nconst onAddSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_ADD_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onAddFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_ADD_FAILURE\r\n });\r\n};\r\n\r\nexport const onEdit = payload => dispatch => {\r\n let service = HttpService();\r\n dispatch({ type: ActionTypes.ADMIN_PROMO_CODES_EDIT_REQUEST });\r\n service\r\n .editPromoCode(payload)\r\n .then(() => {\r\n dispatch(onEditSuccess(payload));\r\n dispatch(addNotification(\"Promo code has been successfully edited.\"));\r\n })\r\n .catch(() => {\r\n dispatch(onEditFailure());\r\n dispatch(\r\n addNotification(\"There was an error updating the promo code\", \"warning\")\r\n );\r\n });\r\n};\r\n\r\nconst onEditSuccess = payload => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_EDIT_SUCCESS,\r\n payload\r\n });\r\n};\r\n\r\nconst onEditFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_EDIT_FAILURE\r\n });\r\n};\r\n\r\nconst onDeleteFailure = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.ADMIN_PROMO_CODES_DELETE_FAILURE\r\n });\r\n};\r\n\r\nexport const toggleDeleteDialog = payload => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_SHOW_DELETE_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleEditDialog = payload => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_SHOW_EDIT_DIALOG,\r\n payload\r\n});\r\n\r\nexport const toggleAddDialog = payload => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_SHOW_EDIT_DIALOG,\r\n payload\r\n});\r\n\r\nexport const formInputChange = (name, value, error) => ({\r\n type: ActionTypes.ADMIN_PROMO_CODES_DIALOG_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport { withRouter } from \"react-router-dom\";\r\nimport PromoCodes from \"./promo-codes\";\r\nimport * as dataTableActionCreators from \"./redux/datatable/action-creators\";\r\nimport * as dialogActionCreators from \"./redux/dialog/action-creators\";\r\nimport * as sysActionCreators from \"../../../redux/system/system-action-creators\";\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n dataTable: state.promoCode.DataTable,\r\n dialog: state.promoCode.Dialog\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLoad: () => dispatch(dataTableActionCreators.onLoad()),\r\n toggleEditDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleEditDialog(payload)),\r\n toggleDeleteDialog: (payload) =>\r\n dispatch(dialogActionCreators.toggleDeleteDialog(payload)),\r\n toggleAddDialog: () => dispatch(dialogActionCreators.toggleEditDialog()),\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(dataTableActionCreators.formInputChange(name, value, error));\r\n },\r\n onDialogInputChange: ({ name, value, error }) => {\r\n dispatch(dialogActionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: (error) =>\r\n dispatch(sysActionCreators.addNotification(error, \"warning\")),\r\n onDelete: (payload) => dispatch(dialogActionCreators.onDelete(payload)),\r\n onEdit: (payload) => dispatch(dialogActionCreators.onEdit(payload)),\r\n onAdd: (payload) => dispatch(dialogActionCreators.onAdd(payload)),\r\n onSettingsChanged: (settings) => {\r\n dispatch(dataTableActionCreators.keepDataTableSettings(settings));\r\n },\r\n clearDataTableSearchbox: () =>\r\n dispatch(dataTableActionCreators.clearDataTableSearchboxFilter()),\r\n dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n loadRequest: payload => {\r\n dispatchProps.dispatch(dataTableActionCreators.loadRequest(payload));\r\n }\r\n});\r\n\r\nconst PromoCodesContainer = withRouter(\r\n connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n )(PromoCodes)\r\n);\r\n\r\nexport default PromoCodesContainer;\r\n","import React, { Component } from \"react\";\r\n\r\nclass AppWrapper extends Component {\r\n render() {\r\n const { children } = this.props;\r\n const { loggedIn } = this.props.loginData;\r\n\r\n return (\r\n \r\n {children}\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default AppWrapper;\r\n","import { connect } from \"react-redux\";\r\nimport { selectLoginData } from \"../../../redux/system/login-reducer\";\r\nimport AppWrapper from \"./App-Wrapper\";\r\n\r\nfunction mapStateToProps(state) {\r\n const loginData = selectLoginData(state);\r\n\r\n return {\r\n loginData: loginData\r\n };\r\n}\r\n\r\nconst AppWrapperContainer = connect(mapStateToProps)(AppWrapper);\r\n\r\nexport default AppWrapperContainer;\r\n","/**\r\n * Login Impersonation Component\r\n * - grabs the token and user id to send back to server\r\n * - if successfull server will respond a valid jwt\r\n * rcnet @solvable 2019\r\n */\r\nimport React, { useEffect } from \"react\";\r\nimport { Redirect } from \"react-router-dom\";\r\nimport { connect } from \"react-redux\";\r\nimport { selectLoginData } from \"../../../redux/system/login-reducer\";\r\nimport * as actionCreators from \"../../../redux/system/system-action-creators\";\r\nimport ContentSection from \"../../Content-Section/index\";\r\nimport BlockUiFx from \"./../Block-Ui-Fx/Block-Ui-Fx\";\r\n\r\n// Functional component with react hooks\r\nconst LoginImpersonationContainer = ({\r\n urlRedirectionViaImpersonation,\r\n match,\r\n onLogin,\r\n}) => {\r\n // redirectNow =false;\r\n\r\n useEffect(() => {\r\n const { userId, token } = match.params;\r\n onLogin(userId, token);\r\n }, []);\r\n\r\n return (\r\n <>\r\n {urlRedirectionViaImpersonation !== \"\" ? (\r\n \r\n ) : (\r\n \r\n \r\n \r\n
Logging in please wait... \r\n \r\n \r\n \r\n )}\r\n >\r\n );\r\n};\r\n\r\n// ---------------\r\n// Redux-Connect\r\n// ---------------\r\nconst mapStateToProps = (state) => {\r\n const { urlRedirectionViaImpersonation } = selectLoginData(state);\r\n return { urlRedirectionViaImpersonation };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onLogin: (id, token) => {\r\n dispatch(actionCreators.loginImpersonationInit());\r\n dispatch(actionCreators.onImpersonateLogin(id, token, ownProps.history));\r\n },\r\n});\r\n\r\nexport default connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n)(LoginImpersonationContainer);\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nclass AuthoriseAvs extends Component {\r\n componentDidMount() {\r\n const { onLoadForm } = this.props;\r\n\r\n onLoadForm();\r\n }\r\n\r\n render() {\r\n const { isLoading, onSubmit } = this.props;\r\n const {\r\n userCode,\r\n deviceCode,\r\n verificationUrl,\r\n errorMessage,\r\n } = this.props.authoriseAvs;\r\n\r\n return (\r\n <>\r\n \r\n \r\n Avetmiss Validation Service | Authorise \r\n \r\n The security token this website uses to communicate with the\r\n Avetmiss Validation Service has expired.\r\n \r\n \r\n \r\n \r\n Please click the link below, and enter the code listed below. Once\r\n you have authorised the website, please click the 'Verify Access'\r\n button below to verify this website can access the Avetmiss\r\n Validation Service. Please note, you will need to be logged into the\r\n Avetmiss Validation Service with an admin account before you click\r\n the link below.\r\n
\r\n \r\n \r\n {verificationUrl}\r\n \r\n
\r\n {userCode} \r\n onSubmit(deviceCode)}\r\n >\r\n Verify Access\r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default AuthoriseAvs;\r\n","/**\r\n * Avetmiss Reporting Authorise AVS Service\r\n */\r\nimport HttpClient from \"../../../coreLib/http/httpClient\";\r\n\r\nconst AuthoriseAvsService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = () => {\r\n return httpClient.get(\"/v1/avetmiss/status\");\r\n };\r\n\r\n const getAuthorisation = () => {\r\n return httpClient.get(\"/v1/avetmiss/authorise\");\r\n };\r\n\r\n const getVerification = deviceCode => {\r\n return httpClient.get(`/v1/avetmiss/verify/${deviceCode}`);\r\n };\r\n\r\n return {\r\n getStatus,\r\n getAuthorisation,\r\n getVerification\r\n };\r\n};\r\n\r\nexport default AuthoriseAvsService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport AuthoriseAvsService from \"../authorise-avs-service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\nexport const onLoadForm = history => {\r\n return dispatch => {\r\n dispatch(LoadFormRequest());\r\n\r\n const service = AuthoriseAvsService();\r\n\r\n service\r\n .getStatus()\r\n .then(resp => {\r\n if (resp.data.validToken) {\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n return;\r\n }\r\n\r\n service\r\n .getAuthorisation()\r\n .then(resp => {\r\n dispatch(\r\n LoadFormSuccess(\r\n resp.data.userCode,\r\n resp.data.deviceCode,\r\n resp.data.verificationUrl,\r\n resp.data.errorMessage\r\n )\r\n );\r\n })\r\n .catch(err => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, an error occurred trying to get the Avetmiss Reporting Authorisation Details.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n })\r\n .catch(err => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, an error occurred trying to get the Avetmiss Reporting Authorisation Details.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst LoadFormRequest = () => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_LOAD_FORM_REQUEST\r\n});\r\n\r\nconst LoadFormSuccess = (\r\n userCode,\r\n deviceCode,\r\n verificationUrl,\r\n errorMessage\r\n) => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_LOAD_FORM_SUCCESS,\r\n payload: {\r\n userCode,\r\n deviceCode,\r\n verificationUrl,\r\n errorMessage\r\n }\r\n});\r\n\r\nconst LoadFormFailure = () => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_LOAD_FORM_FAILURE\r\n});\r\n\r\n// Async\r\nexport const onSubmit = (deviceCode, history) => dispatch => {\r\n dispatch(onSubmitRequest());\r\n\r\n const service = AuthoriseAvsService();\r\n\r\n service\r\n .getVerification(deviceCode)\r\n .then(resp => {\r\n if (resp.data.verificationSuccessful) {\r\n dispatch(onSubmitSuccess());\r\n dispatch(\r\n addNotification(\r\n \"Awesome, that worked, we are set for another year.\",\r\n \"info\"\r\n )\r\n );\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n }\r\n })\r\n .catch(err => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\r\n \"Hmm, that did not work. Try again, and if you keep getting this error, you might need to call support.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_SUBMIT_REQUEST\r\n});\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_SUBMIT_SUCCESS\r\n});\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.AVETMISS_AUTHORISE_AVS_SUBMIT_FAILURE\r\n});\r\n","import { connect } from \"react-redux\";\r\nimport AuthoriseAvs from \"./authorise-avs\";\r\nimport { selectAuthoriseAvs } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const authoriseAvs = selectAuthoriseAvs(state);\r\n\r\n return {\r\n authoriseAvs: authoriseAvs,\r\n isLoading: authoriseAvs.isLoading\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n dispatch: dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadForm: () => {\r\n dispatchProps.dispatch(actionCreators.onLoadForm(dispatchProps.history));\r\n },\r\n onSubmit: deviceCode => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmit(deviceCode, dispatchProps.history)\r\n );\r\n }\r\n});\r\n\r\nconst AuthoriseAvsContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(AuthoriseAvs);\r\n\r\nexport default AuthoriseAvsContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Row, Col, Form, FormGroup } from \"reactstrap\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport SelectField from \"../../../components/Common/Fields/Select-Field\";\r\nimport KeyboardEventHandler from \"react-keyboard-event-handler\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport * as Constants from \"../../../constants\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nclass AvetmissReporting extends Component {\r\n componentDidMount() {\r\n const { onLoadForm } = this.props;\r\n\r\n onLoadForm();\r\n }\r\n\r\n render() {\r\n const form = formHandler();\r\n\r\n const { onSubmit, onInputChange, onFieldError, isLoading } = this.props;\r\n\r\n const {\r\n years,\r\n periods,\r\n collectionStartDate,\r\n collectionEndDate,\r\n version,\r\n } = this.props.avetmissReporting;\r\n\r\n const { state, year, period } = this.props.avetmissReporting.fields;\r\n\r\n return (\r\n <>\r\n \r\n \r\n Avetmiss Validation Service | Reporting \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n val !== \"-1\" && val !== \"\"\r\n ? false\r\n : \"Select a valid state\"\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n >\r\n All States \r\n {Constants.australianStates.map((item, i) => (\r\n \r\n {item.label}\r\n \r\n ))}\r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n \r\n val !== \"-1\" && val !== \"\" ? false : \"Select a Year\"\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n >\r\n - Select a Year - \r\n {years.map((item, i) => (\r\n \r\n {item}\r\n \r\n ))}\r\n \r\n \r\n \r\n
\r\n\r\n {year && (\r\n \r\n \r\n \r\n \r\n val !== \"-1\" && val !== \"\" ? false : \"Select a Period\"\r\n }\r\n onFieldError={onFieldError}\r\n ref={form.add}\r\n >\r\n - Select a Period - \r\n {periods.map((item, i) => (\r\n \r\n {item}\r\n \r\n ))}\r\n \r\n \r\n \r\n
\r\n )}\r\n\r\n {year && period && (\r\n \r\n \r\n \r\n \r\n
Avetmiss Version \r\n
{version}
\r\n
Collection Period \r\n
\r\n {collectionStartDate} - {collectionEndDate}\r\n
\r\n
\r\n \r\n \r\n
\r\n )}\r\n \r\n {\r\n form.validate({\r\n validFn: () =>\r\n onSubmit(\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period\r\n ),\r\n invalidFn: () => console.log(form.getFieldErrors()),\r\n });\r\n }}\r\n >\r\n Generate NAT Files\r\n \r\n \r\n \r\n form.validate({\r\n validFn: () =>\r\n onSubmit(\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period\r\n ),\r\n })\r\n }\r\n />\r\n \r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default AvetmissReporting;\r\n","/**\r\n * Avetmiss Reporting Service\r\n */\r\nimport HttpClient from \"../../../coreLib/http/httpClient\";\r\n\r\nconst AvetmissReportingService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = () => {\r\n return httpClient.get(\"/v1/avetmiss/status\");\r\n };\r\n\r\n const getCollectionTypes = () => {\r\n return httpClient.get(\"/v1/avetmiss/collections\");\r\n };\r\n\r\n const submitRequest = payload => {\r\n return httpClient.post(\"/v1/avetmiss/compile\", payload);\r\n };\r\n\r\n return {\r\n getStatus,\r\n getCollectionTypes,\r\n submitRequest\r\n };\r\n};\r\n\r\nexport default AvetmissReportingService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport AvetmissReportingService from \"../avetmiss-reporting-service\";\r\nimport uniq from \"lodash/uniq\";\r\nimport moment from \"moment\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadForm = history => {\r\n return dispatch => {\r\n dispatch(LoadFormRequest());\r\n\r\n const service = AvetmissReportingService();\r\n\r\n service\r\n .getStatus()\r\n .then(resp => {\r\n if (!resp.data.validToken) {\r\n history.push(\"/Admin/Avetmiss/Authorise/\");\r\n return;\r\n }\r\n\r\n if (\r\n resp.status !== 204 &&\r\n resp.data.reports !== null &&\r\n resp.data.reports !== [] &&\r\n resp.data.reports.length > 0\r\n ) {\r\n history.push(\"/Admin/Avetmiss/Submission/\");\r\n return;\r\n }\r\n\r\n service\r\n .getCollectionTypes()\r\n .then(resp => {\r\n const years = resp.data.map(collection => collection.year);\r\n const uniqueYears = uniq(years);\r\n\r\n dispatch(LoadFormSuccess(uniqueYears, resp.data));\r\n })\r\n .catch(err => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, an error occurred trying to get the Avetmiss Reporting Collection Types.\",\r\n \"error\"\r\n )\r\n );\r\n\r\n if (\r\n err.response.data.Message ===\r\n \"The NCVER API returned an unauthorised response. You will need to login again.\"\r\n )\r\n history.push(\"/Admin/Avetmiss/Authorise/\");\r\n });\r\n })\r\n .catch(err => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, an error occurred trying to get the Avetmiss Reporting Collection Types.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst LoadFormRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_LOAD_FORM_REQUEST\r\n});\r\n\r\nconst LoadFormSuccess = (years, collections) => ({\r\n type: ActionTypes.AVETMISS_REPORTING_LOAD_FORM_SUCCESS,\r\n payload: {\r\n years,\r\n collections\r\n }\r\n});\r\n\r\nconst LoadFormFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_LOAD_FORM_FAILURE\r\n});\r\n\r\n// Async\r\nexport const onSubmit = (\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period,\r\n history\r\n) => dispatch => {\r\n dispatch(onSubmitRequest());\r\n\r\n const service = AvetmissReportingService();\r\n\r\n let model = {\r\n collectionStartDate: moment(collectionStartDate, \"DD/MM/YYYY\").format(\r\n \"YYYY-MM-DD\"\r\n ),\r\n collectionEndDate: moment(collectionEndDate, \"DD/MM/YYYY\").format(\r\n \"YYYY-MM-DD\"\r\n ),\r\n state,\r\n year,\r\n period,\r\n version\r\n };\r\n\r\n service\r\n .submitRequest(model)\r\n .then(resp => {\r\n dispatch(onSubmitSuccess());\r\n dispatch({\r\n type: \"AVETMISS_REPORTING_SUBMISSION_LOAD_FORM_SUCCESS\",\r\n payload: {\r\n files: resp.data.reports,\r\n year: resp.data.year,\r\n period: resp.data.period,\r\n version: resp.data.version,\r\n collectionStartDate: collectionStartDate,\r\n collectionEndDate: collectionEndDate,\r\n state: state,\r\n },\r\n });\r\n history.push(\"/Admin/Avetmiss/Submission/\");\r\n })\r\n .catch(err => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\"There was an issue generating the NAT files.\", \"error\")\r\n );\r\n });\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMIT_REQUEST\r\n});\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMIT_SUCCESS\r\n});\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMIT_FAILURE\r\n});\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => {\r\n return (dispatch, getState) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_FORM_INPUT_CHANGE,\r\n payload: {\r\n name: name,\r\n value: value,\r\n error: error\r\n }\r\n });\r\n\r\n switch (name) {\r\n case \"year\":\r\n const periods = getState()\r\n .avetmissReporting.collections.filter(c => c.year === value)\r\n .map(collection => collection.period);\r\n\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_YEAR_CHANGE,\r\n payload: periods\r\n });\r\n break;\r\n\r\n case \"period\":\r\n if (value === \"\") return;\r\n\r\n const collections = getState()\r\n .avetmissReporting.collections.filter(\r\n c =>\r\n c.year === getState().avetmissReporting.fields.year &&\r\n c.period === value\r\n )\r\n .map(collection => ({\r\n collectionStartDate: moment(collection.collectionStartDate).format(\r\n \"DD/MM/YYYY\"\r\n ),\r\n collectionEndDate: moment(collection.collectionEndDate).format(\r\n \"DD/MM/YYYY\"\r\n ),\r\n version: collection.version\r\n }));\r\n\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_PERIOD_CHANGE,\r\n payload: collections[0]\r\n });\r\n break;\r\n default:\r\n break;\r\n }\r\n };\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport AvetmissReporting from \"./avetmiss-reporting\";\r\nimport { selectAvetmissReporting } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport { addNotification } from \"../../../redux/system/system-action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const avetmissReporting = selectAvetmissReporting(state);\r\n\r\n return {\r\n avetmissReporting: avetmissReporting,\r\n isLoading: avetmissReporting.isLoading\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n onFieldError: error => dispatch(addNotification(error, \"Error\")),\r\n dispatch: dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadForm: () => {\r\n dispatchProps.dispatch(actionCreators.onLoadForm(dispatchProps.history));\r\n },\r\n onSubmit: (\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period\r\n ) => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmit(\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n }\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n\r\n if (!fields.state) return true;\r\n if (!fields.collectionStartDate) return true;\r\n if (!fields.collectionEndDate) return true;\r\n if (!fields.version) return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst AvetmissReportingContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(AvetmissReporting);\r\n\r\nexport default AvetmissReportingContainer;\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n render() {\r\n const {\r\n toggleDeleteDialog,\r\n showDeleteDialog,\r\n isDeleting,\r\n onDelete\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete NAT Files\r\n \r\n \r\n \r\n Are you sure you want to delete the NAT files? Please note, this\r\n will delete any manual changes you have made. This cannot be\r\n undone.\r\n \r\n \r\n \r\n onDelete()}\r\n className=\"ttg-btn\"\r\n isLoading={isDeleting}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","const IconFactory = () => {\r\n const getIcon = type => {\r\n switch (type) {\r\n case \"pdf\":\r\n return \"fas fa-file-pdf pdf\";\r\n case \"doc\":\r\n case \"docx\":\r\n return \"fas fa-file-word word\";\r\n case \"xls\":\r\n case \"xlsx\":\r\n return \"fas fa-file-excel excel\";\r\n case \"jpg\":\r\n case \"JPG\":\r\n case \"jpeg\":\r\n case \"png\":\r\n case \"gif\":\r\n case \"bmp\":\r\n return \"fas fa-file-image image\";\r\n default:\r\n return \"fas fa-file file\";\r\n }\r\n };\r\n\r\n return {\r\n getIcon\r\n };\r\n};\r\n\r\nexport default IconFactory;\r\n","const getColor = (props) => {\r\n if (props.isDragAccept) {\r\n return \"#43325d\";\r\n }\r\n if (props.validForReject) {\r\n // && props.isDragReject\r\n return \"#ff1744\";\r\n }\r\n if (props.isDragActive) {\r\n return \"#2196f3\";\r\n }\r\n return \"#eeeeee\";\r\n};\r\n\r\nconst toKilobyte = (fileSize) => {\r\n if (fileSize === \"-\") return \"0\";\r\n if (fileSize <= 0) return 0;\r\n return (fileSize / 1024).toFixed(2);\r\n};\r\n\r\nconst readFileAsync = async (inputFile) => {\r\n let reader = new FileReader();\r\n return new Promise((resolve) => {\r\n let { name, size } = inputFile;\r\n reader.onload = function (e) {\r\n resolve({\r\n name,\r\n size,\r\n data: e.target.result,\r\n });\r\n };\r\n reader.readAsDataURL(inputFile);\r\n });\r\n};\r\n\r\nasync function fileListToBase64(fileList, roundOffSize) {\r\n // create function which return resolved promise\r\n // with data:base64 string\r\n function getBase64(file) {\r\n if (file.type === \"init\") {\r\n return new Promise((res, rej) => {\r\n res({ name: file.name, data: file.preview, size: file.size });\r\n });\r\n }\r\n\r\n const reader = new FileReader();\r\n\r\n return new Promise((resolve) => {\r\n reader.onloadend = (ev) => {\r\n resolve({\r\n name: file.name,\r\n origFileName: file.name,\r\n preview: ev.target.result,\r\n data: ev.target.result,\r\n size: roundOffSize ? Math.round(file.size / 1024) : file.size,\r\n type: \"new\",\r\n });\r\n };\r\n reader.readAsDataURL(file);\r\n });\r\n }\r\n // here will be array of promisified functions\r\n const promises = [];\r\n\r\n // loop through fileList with for loop\r\n for (let i = 0; i < fileList.length; i++) {\r\n promises.push(getBase64(fileList[i]));\r\n }\r\n\r\n // array with base64 strings\r\n return await Promise.all(promises);\r\n}\r\n\r\nasync function fileToBase64(file, roundOffSize) {\r\n // create function which return resolved promise\r\n // with data:base64 string\r\n function getBase64(file) {\r\n if (file.type === \"init\") {\r\n return new Promise((res, rej) => {\r\n res({ name: file.name, data: file.preview, size: file.size });\r\n });\r\n }\r\n\r\n const reader = new FileReader();\r\n\r\n return new Promise((resolve) => {\r\n reader.onloadend = (ev) => {\r\n resolve({\r\n name: file.name,\r\n origFileName: file.name,\r\n preview: ev.target.result,\r\n data: ev.target.result,\r\n size: roundOffSize ? Math.round(file.size / 1024) : file.size,\r\n type: \"new\",\r\n });\r\n };\r\n reader.readAsDataURL(file);\r\n });\r\n }\r\n\r\n // array with base64 strings\r\n return await getBase64(file);\r\n}\r\n\r\nconst mapFiles = (files) =>\r\n files.map((file) => {\r\n let { name, origFileName, data, size } = file;\r\n\r\n return {\r\n name,\r\n origFileName,\r\n data,\r\n size,\r\n };\r\n });\r\n\r\nexport {\r\n fileListToBase64,\r\n toKilobyte,\r\n getColor,\r\n readFileAsync,\r\n fileToBase64,\r\n mapFiles,\r\n};\r\n","import React from \"react\";\r\nimport { Lightbox } from \"react-modal-image\";\r\n\r\nconst ImagePreviewFx = ({\r\n isOpen,\r\n imageLargeUrl,\r\n showRotate,\r\n closePreview,\r\n alternateText\r\n}) => {\r\n return (\r\n <>\r\n {isOpen && (\r\n \r\n )}\r\n >\r\n );\r\n};\r\n\r\nexport default ImagePreviewFx;\r\n","/* eslint-disable react-hooks/exhaustive-deps */\r\nimport React, { useEffect, useState, useCallback } from \"react\";\r\nimport { PropTypes } from \"prop-types\";\r\nimport {\r\n Container,\r\n Row,\r\n Col,\r\n Button,\r\n Card,\r\n CardBody,\r\n CardFooter,\r\n} from \"reactstrap\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport \"./file-uploader.scss\";\r\nimport styled from \"styled-components\";\r\nimport IconFactory from \"./service/icon-factory\";\r\nimport { fileListToBase64, toKilobyte, getColor } from \"./service/helper\";\r\nimport ImagePreviewFx from \"./../image-preview-fx/image-preview-fx\";\r\nimport ToolTipFx from \"./../tooltip/tool-tip-fx\";\r\nimport BlockUiFx from \"../Block-Ui-Fx/Block-Ui-Fx\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nconst StyledContainer = styled.div`\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n padding: 20px;\r\n border-width: 2px;\r\n border-radius: 2px;\r\n border-color: ${(props) => getColor(props)};\r\n border-style: dashed;\r\n background-color: #fafafa;\r\n color: #bdbdbd;\r\n outline: none;\r\n transition: border 0.24s ease-in-out;\r\n`;\r\n\r\nconst FileUploader = (props) => {\r\n const [files, setFiles] = useState([]);\r\n const [isPreviewOpen, setPreviewOpen] = useState(false);\r\n const [previewUrl, setPreviewUrl] = useState(\"\");\r\n const [isDropping, toggleDrop] = useState(false);\r\n const [initialised, initialise] = useState(false);\r\n const {\r\n text,\r\n dropText,\r\n minSize,\r\n maxFileSize,\r\n maxFiles,\r\n initialFiles,\r\n mode,\r\n fileTypes,\r\n isReadonly,\r\n cloudStoragePath,\r\n onChange,\r\n } = props;\r\n\r\n const onDrop = useCallback(async (acceptedFiles) => {\r\n // Reject files exceeding the maxFiles limit\r\n\r\n toggleDrop(true);\r\n let finalAcceptedFiles = [];\r\n let filesCount = files.length + acceptedFiles.length;\r\n if (filesCount > maxFiles) {\r\n let itemsUpperLimit = maxFiles - files.length;\r\n finalAcceptedFiles = acceptedFiles.slice(0, itemsUpperLimit);\r\n } else {\r\n finalAcceptedFiles = acceptedFiles;\r\n }\r\n\r\n let additionalFiles = finalAcceptedFiles.map((file) =>\r\n Object.assign(file, {\r\n preview: URL.createObjectURL(file),\r\n })\r\n );\r\n\r\n // Convert to base64 each file\r\n let arrayOfBase64Files = await fileListToBase64(additionalFiles);\r\n\r\n arrayOfBase64Files = arrayOfBase64Files.map((x) => ({\r\n ...x,\r\n size: x.size / 1024 < 0 ? x.size : x.size / 1024,\r\n }));\r\n\r\n files.push(...arrayOfBase64Files);\r\n setFiles(files);\r\n\r\n onChange([...files]);\r\n toggleDrop(false);\r\n });\r\n\r\n const getFileTypesAccepted = () => {\r\n if (mode === \"Image\" && fileTypes.length === 0) return \"image/*\";\r\n if (mode === \"File\" && fileTypes.length === 0) {\r\n return [\r\n \".doc\",\r\n \".docx\",\r\n \".xls\",\r\n \".xlsx\",\r\n \".pdf\",\r\n \".jpg\",\r\n \".jpeg\",\r\n \".png\",\r\n ].join(\",\");\r\n } else {\r\n return fileTypes.join(\",\");\r\n }\r\n };\r\n\r\n const {\r\n getRootProps,\r\n getInputProps,\r\n isDragActive,\r\n isDragAccept,\r\n isDragReject,\r\n rejectedFiles,\r\n } = useDropzone({\r\n accept: getFileTypesAccepted(),\r\n minSize: minSize,\r\n maxSize: maxFileSize,\r\n //multiple: true,\r\n onDrop,\r\n disabled: isReadonly,\r\n });\r\n\r\n const openPreview = (file) => {\r\n setPreviewUrl(file.preview);\r\n setPreviewOpen(true);\r\n };\r\n\r\n const removeFile = useCallback((file) => () => {\r\n if (isReadonly) return;\r\n URL.revokeObjectURL(file.preview);\r\n let filesUpdated = files.filter((o) => o !== file);\r\n setFiles(filesUpdated);\r\n\r\n onChange([...filesUpdated]);\r\n });\r\n\r\n const closePreview = (e) => {\r\n setPreviewOpen(false);\r\n };\r\n\r\n const downloadFile = (file) => {\r\n saveAs(file.preview, file.name);\r\n };\r\n\r\n // Refactor: Separate file\r\n const imageListing = files.map((file, index) => (\r\n \r\n
\r\n
\r\n
openPreview(file)}\r\n alt=\"\"\r\n />\r\n
Open preview \r\n
\r\n
\r\n
\r\n
\r\n Filename \r\n
\r\n
\r\n {file.name} \r\n
\r\n
\r\n Size \r\n
\r\n
\r\n \r\n {file.size > 1024 ? toKilobyte(file.size) : Math.round(file.size)}{\" \"}\r\n Kb\r\n \r\n
\r\n
\r\n {!isReadonly && (\r\n \r\n Remove\r\n \r\n )}\r\n
\r\n
\r\n
\r\n ));\r\n\r\n const limitFileName = (fileName) => {\r\n if (fileName.length > 18) {\r\n let name = fileName.substring(0, fileName.lastIndexOf(\".\"));\r\n let extension = fileName.substring(fileName.lastIndexOf(\".\"));\r\n return `${name.substring(0, 16)}...${extension}`;\r\n }\r\n return fileName;\r\n };\r\n\r\n const isAnImage = (ext) => {\r\n switch (ext) {\r\n case \"jpg\":\r\n case \"jpeg\":\r\n case \"png\":\r\n case \"JPG\":\r\n case \"JPEG\":\r\n case \"PNG\":\r\n return true;\r\n default:\r\n return false;\r\n }\r\n };\r\n\r\n // Refactor: Separate file\r\n const fileListing = files.map((file, index) => {\r\n const ext = file.name.substring(file.name.lastIndexOf(\".\") + 1);\r\n const icon = IconFactory().getIcon(ext);\r\n let limitedName = limitFileName(file.name);\r\n const fileIsAnImage = isAnImage(ext);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n Remove \r\n
\r\n \r\n \r\n {fileIsAnImage && (\r\n <>\r\n openPreview(file)}\r\n alt=\"\"\r\n style={{ cursor: \"pointer\" }}\r\n />\r\n \r\n Open preview\r\n \r\n >\r\n )}\r\n {!fileIsAnImage && (\r\n <>\r\n downloadFile(file)\r\n : () => {}\r\n }\r\n style={file.type === \"init\" ? { cursor: \"pointer\" } : {}}\r\n />\r\n {file.type === \"init\" && (\r\n \r\n Download\r\n \r\n )}\r\n >\r\n )}\r\n \r\n
\r\n \r\n \r\n \r\n \r\n {limitedName} \r\n \r\n {\" \"}\r\n ({Math.round(file.size)} kb)\r\n \r\n \r\n
\r\n \r\n \r\n \r\n );\r\n });\r\n\r\n const DragMessage = ({ isDragActive, isDragReject, rejected }) => {\r\n return (\r\n <>\r\n \r\n {!isDragActive && !rejected && (\r\n \r\n {text} Maximum of {maxFiles} file{maxFiles > 1 ? \"s\" : \"\"}.\r\n {files.length > 0 ? (\r\n <>\r\n \r\n \r\n {files.length} file(s) attached.\r\n \r\n >\r\n ) : null}\r\n
\r\n )}\r\n {isDragActive && !rejected && (\r\n \r\n {dropText}\r\n
\r\n )}\r\n {rejected && (\r\n \r\n File type is not supported.\r\n
\r\n )}\r\n \r\n >\r\n );\r\n };\r\n\r\n const FileTooLarge = () => {\r\n const isFileTooLarge =\r\n rejectedFiles.length > 0 && rejectedFiles[0].size > maxFileSize;\r\n return (\r\n <>{isFileTooLarge && File is too large.
}>\r\n );\r\n };\r\n\r\n const reloadInitialFiles = () => {\r\n if (!initialFiles || initialFiles.length <= 0) return;\r\n\r\n setFiles(\r\n initialFiles.map((o) =>\r\n Object.assign(\r\n {},\r\n {\r\n type: \"init\",\r\n name: o.name,\r\n size: o.size,\r\n data: o.data || null,\r\n preview: getPreviewData(o),\r\n }\r\n )\r\n )\r\n );\r\n };\r\n\r\n const getPreviewData = (file) => {\r\n if (file.data.includes(\"data:\")) return file.data;\r\n return `${cloudStoragePath}/${file.name}`;\r\n };\r\n\r\n const isImageMode = () => mode === \"Image\";\r\n\r\n // Component did mount\r\n useEffect(() => {\r\n if (initialFiles.length > 0 && !initialised) {\r\n initialise(true);\r\n reloadInitialFiles();\r\n }\r\n }, [initialFiles]);\r\n\r\n useEffect(\r\n () => () => {\r\n // Make sure to revoke the data uris to avoid memory leaks\r\n files.forEach((file) => URL.revokeObjectURL(file.preview));\r\n },\r\n [files]\r\n );\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n 0 ? true : false\r\n }\r\n className=\"mb-2\"\r\n >\r\n \r\n 0 ? true : false\r\n }\r\n />\r\n \r\n \r\n {isImageMode() ? (\r\n \r\n ) : (\r\n {fileListing}
\r\n )}\r\n \r\n
\r\n \r\n );\r\n};\r\n\r\nexport default FileUploader;\r\n\r\nFileUploader.propTypes = {\r\n minSize: PropTypes.number,\r\n maxFileSize: PropTypes.number,\r\n maxFiles: PropTypes.number,\r\n mode: PropTypes.string, //Note: Mode can be Image or File, each mode has different layout and behavior\r\n fileTypes: PropTypes.array,\r\n initialFiles: PropTypes.array,\r\n isReadonly: PropTypes.bool,\r\n cloudStoragePath: PropTypes.string,\r\n onChange: PropTypes.func.isRequired,\r\n xs: PropTypes.any,\r\n sm: PropTypes.any,\r\n md: PropTypes.any,\r\n lg: PropTypes.any,\r\n xl: PropTypes.any,\r\n};\r\n\r\nFileUploader.defaultProps = {\r\n minSize: 0,\r\n maxFileSize: 100000, // 100kb default\r\n maxFiles: 5,\r\n mode: \"File\",\r\n fileTypes: [],\r\n initialFiles: [],\r\n cloudStoragePath: \"\",\r\n isReadonly: false,\r\n xs: 6,\r\n sm: 6,\r\n md: 6,\r\n lg: 6,\r\n xl: 6,\r\n};\r\n","import React from \"react\";\r\nimport { ErrorMessage } from 'formik';\r\nimport \"./validation-error-message.scss\";\r\n\r\nconst ValidationErrorMessage = ({name}) => (\r\n \r\n {msg => {msg}
}\r\n \r\n);\r\n\r\nexport default ValidationErrorMessage;","import React, { useEffect } from \"react\";\r\nimport { Button, Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport { withFormik, Form } from \"formik\";\r\nimport FileUploader from \"./../../../../../../components/Common/file-uploader/file-uploader\";\r\nimport ValidationErrorMessage from \"./../../../../../../components/Common/validation-error-message/validation-error-message\";\r\nimport * as Yup from \"yup\";\r\n\r\nconst ImportNatFileDialog = ({\r\n isOpen,\r\n isImporting,\r\n close,\r\n resetForm,\r\n handleSubmit,\r\n values,\r\n data,\r\n setValues,\r\n setFieldValue,\r\n}) => {\r\n useEffect(() => {\r\n if (data) {\r\n setValues({\r\n id: data.id,\r\n title: data.title,\r\n displayOrder: data.displayOrder,\r\n files: [\r\n {\r\n ...data.file,\r\n size: data.file.size,\r\n },\r\n ],\r\n });\r\n }\r\n }, [data, setValues]);\r\n\r\n const closeDialog = () => {\r\n if (!isImporting) {\r\n close();\r\n resetForm();\r\n }\r\n };\r\n\r\n return (\r\n \r\n Import NAT files \r\n \r\n \r\n {\r\n setFieldValue(\r\n \"files\",\r\n files.map(({ name, data, size }) => {\r\n return {\r\n name,\r\n data,\r\n size,\r\n };\r\n })\r\n );\r\n }}\r\n xs=\"12\"\r\n sm=\"12\"\r\n md=\"12\"\r\n lg=\"12\"\r\n xl=\"12\"\r\n />\r\n\r\n \r\n \r\n {!isImporting && (\r\n \r\n \r\n Upload\r\n \r\n {\r\n e.preventDefault();\r\n closeDialog();\r\n }}\r\n >\r\n Cancel\r\n \r\n \r\n )}\r\n \r\n \r\n );\r\n};\r\n\r\nconst ImportNatFileFormDialog = withFormik({\r\n mapPropsToValues: () => ({ files: \"\" }),\r\n validationSchema: Yup.object().shape({\r\n files: Yup.array()\r\n .required(\"Please add a file.\")\r\n .min(1, \"Please add a file.\"),\r\n }),\r\n handleSubmit: async (values, { props, resetForm, setSubmitting }) => {\r\n try {\r\n setSubmitting(true);\r\n await props.import(values.files[0].data);\r\n resetForm();\r\n } catch (error) {\r\n setSubmitting(false);\r\n }\r\n },\r\n})(ImportNatFileDialog);\r\n\r\nexport default ImportNatFileFormDialog;\r\n","import React, { Component } from \"react\";\r\nimport { FormGroup, Row, Col, Table } from \"reactstrap\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport formHandler from \"../../../components/Common/Fields/form-handler\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport DeleteDialog from \"./delete-dialog\";\r\nimport ImportNatFileFormDialog from \"./components/dialogs/import\";\r\n\r\nclass AvetmissReportingSubmission extends Component {\r\n componentDidMount() {\r\n const { onLoadForm } = this.props;\r\n const { files } = this.props.avetmissReportingSubmission;\r\n\r\n if (!files || files.length === 0) onLoadForm();\r\n }\r\n\r\n render() {\r\n const form = formHandler();\r\n\r\n const {\r\n isLoading,\r\n toggleDeleteDialog,\r\n showDeleteDialog,\r\n isDeleting,\r\n onSubmit,\r\n onDelete,\r\n onImport,\r\n toggleImportDialog,\r\n showImportDialog,\r\n isImporting,\r\n isExporting,\r\n exportNatFiles,\r\n } = this.props;\r\n\r\n const {\r\n files,\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n } = this.props.avetmissReportingSubmission;\r\n return (\r\n <>\r\n \r\n \r\n Avetmiss Validation Service | Submission \r\n \r\n \r\n \r\n Avetmiss Reporting for {period} {year}\r\n \r\n \r\n \r\n \r\n \r\n \r\n File Id \r\n Description \r\n Status \r\n \r\n \r\n \r\n {files.map((file, key) => {\r\n return (\r\n \r\n \r\n {file.filename} \r\n \r\n {file.description} \r\n \r\n {file.generatedSuccessfully\r\n ? \"Generated Successfully\"\r\n : file.errorMessage}\r\n \r\n \r\n );\r\n })}\r\n \r\n
\r\n \r\n
\r\n \r\n {!isDeleting && (\r\n {\r\n form.validate({\r\n validFn: () =>\r\n onSubmit(\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state\r\n ),\r\n invalidFn: () => console.log(form.getFieldErrors()),\r\n });\r\n }}\r\n >\r\n Submit for Validation\r\n \r\n )}\r\n\r\n {!isLoading && (\r\n toggleDeleteDialog()}\r\n >\r\n Delete NAT Files\r\n \r\n )}\r\n\r\n {!isLoading && (\r\n exportNatFiles()}\r\n >\r\n Export NAT Files\r\n \r\n )}\r\n\r\n {!isLoading && (\r\n toggleImportDialog()}\r\n >\r\n Import NAT Files\r\n \r\n )}\r\n \r\n \r\n\r\n \r\n\r\n {\r\n try {\r\n await onImport(value);\r\n } catch (e) {}\r\n }}\r\n />\r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default AvetmissReportingSubmission;\r\n","/**\r\n * Avetmiss Reporting Service\r\n */\r\nimport HttpClient from \"../../../coreLib/http/httpClient\";\r\n\r\nconst AvetmissReportingSubmissionService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = () => {\r\n return httpClient.get(\"/v1/avetmiss/status\");\r\n };\r\n\r\n const submitRequest = payload => {\r\n return httpClient.post(\"/v1/avetmiss/submit\", payload);\r\n };\r\n\r\n const deleteRequest = payload => {\r\n return httpClient.delete(\"/v1/avetmiss\");\r\n };\r\n\r\n const importNatFiles = (file) => {\r\n let payload = {\r\n file: file,\r\n };\r\n\r\n return httpClient.post(\"/v1/avetmiss/nat-files\", payload);\r\n };\r\n\r\n const exportNatFiles = async () => {\r\n const resp = await HttpClient().get(`/v1/avetmiss/download`, {\r\n responseType: \"blob\",\r\n });\r\n\r\n if (resp && resp.status === 200) {\r\n return { data: resp.data, headers: resp.headers };\r\n }\r\n\r\n return null;\r\n };\r\n\r\n return {\r\n getStatus,\r\n submitRequest,\r\n deleteRequest,\r\n importNatFiles,\r\n exportNatFiles,\r\n };\r\n};\r\n\r\nexport default AvetmissReportingSubmissionService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport AvetmissReportingSubmissionService from \"../avetmiss-reporting-submission-service\";\r\nimport { saveAs } from \"file-saver\";\r\nimport { parse } from \"content-disposition\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadForm = (history) => {\r\n return (dispatch) => {\r\n dispatch(LoadFormRequest());\r\n\r\n const service = AvetmissReportingSubmissionService();\r\n\r\n service\r\n .getStatus()\r\n .then((resp) => {\r\n if (!resp.data.validToken) {\r\n history.push(\"/Admin/Avetmiss/Authorise/\");\r\n return;\r\n }\r\n\r\n if (resp.data.reports === null || resp.data.reports === []) {\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n return;\r\n }\r\n\r\n dispatch(\r\n LoadFormSuccess(\r\n resp.data.year,\r\n resp.data.period,\r\n resp.data.version,\r\n resp.data.reports,\r\n resp.data.collectionStartDate,\r\n resp.data.collectionEndDate,\r\n resp.data.state\r\n )\r\n );\r\n })\r\n .catch((err) => {\r\n dispatch(LoadFormFailure());\r\n dispatch(\r\n addNotification(\r\n \"Sorry, an error occurred trying to get the Avetmiss Reporting Collection Types.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst LoadFormRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_LOAD_FORM_REQUEST,\r\n});\r\n\r\nconst LoadFormSuccess = (\r\n year,\r\n period,\r\n version,\r\n reports,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state\r\n) => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_LOAD_FORM_SUCCESS,\r\n payload: {\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n files: reports,\r\n },\r\n});\r\n\r\nconst LoadFormFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_LOAD_FORM_FAILURE,\r\n});\r\n\r\n// Async\r\nexport const onSubmit = (\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n history\r\n) => (dispatch) => {\r\n dispatch(onSubmitRequest());\r\n\r\n const service = AvetmissReportingSubmissionService();\r\n\r\n let model = {\r\n year,\r\n period,\r\n version,\r\n };\r\n\r\n service\r\n .submitRequest(model)\r\n .then((resp) => {\r\n let hasNoAddressErrors = !resp.data.addressErrors?.length;\r\n\r\n dispatch(onSubmitSuccess());\r\n\r\n if (hasNoAddressErrors) {\r\n dispatch({\r\n type: \"AVETMISS_REPORTING_VALIDATION_LOAD_FORM_SUCCESS\",\r\n payload: {\r\n verificationSuccessful: resp.data.verificationSuccessful,\r\n errorMessage: resp.data.errorMessage,\r\n errors: resp.data.errors,\r\n },\r\n });\r\n\r\n history.push(\"/Admin/Avetmiss/Validation/\");\r\n return;\r\n }\r\n\r\n dispatch({\r\n type: \"AVETMISS_ADDRESS_VALIDATION_LOAD_FORM_SUCCESS\",\r\n payload: {\r\n verificationSuccessful: resp.data.verificationSuccessful,\r\n errorMessage: resp.data.errorMessage,\r\n addressErrors: resp.data.addressErrors,\r\n year: year,\r\n period: period,\r\n version: version,\r\n collectionStartDate: collectionStartDate,\r\n collectionEndDate: collectionEndDate,\r\n state: state,\r\n },\r\n });\r\n\r\n history.push(\"/Admin/Avetmiss/Address-Validation\");\r\n })\r\n .catch((err) => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\"There was an issue validating the NAT files.\", \"error\")\r\n );\r\n\r\n if (\r\n err.response.data.Message ===\r\n \"The NCVER API returned an unauthorised response. You will need to login again.\"\r\n )\r\n history.push(\"/Admin/Avetmiss/Authorise/\");\r\n });\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_SUBMIT_REQUEST,\r\n});\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_SUBMIT_SUCCESS,\r\n});\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_SUBMIT_FAILURE,\r\n});\r\n\r\nexport const onDelete = (history) => (dispatch) => {\r\n dispatch(onDeleteRequest());\r\n\r\n const service = AvetmissReportingSubmissionService();\r\n\r\n service\r\n .deleteRequest()\r\n .then((resp) => {\r\n dispatch(onDeleteSuccess());\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n })\r\n .catch((err) => {\r\n dispatch(onDeleteFailure());\r\n dispatch(\r\n addNotification(\"There was an issue deleting the NAT files.\", \"error\")\r\n );\r\n });\r\n};\r\n\r\nconst onDeleteRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_DELETE_REQUEST,\r\n});\r\nconst onDeleteSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_DELETE_SUCCESS,\r\n});\r\nconst onDeleteFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_DELETE_FAILURE,\r\n});\r\n\r\nexport const toggleDeleteDialog = () => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_SHOW_DELETE_DIALOG,\r\n });\r\n};\r\n\r\nexport const toggleImportDialog = () => (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_SHOW_IMPORT_DIALOG,\r\n });\r\n};\r\n\r\nexport const importNatFiles = (file) => async (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_IMPORT_REQUEST,\r\n });\r\n\r\n const service = AvetmissReportingSubmissionService();\r\n\r\n await service\r\n .importNatFiles(file)\r\n .then((resp) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_IMPORT_SUCCESS,\r\n });\r\n\r\n dispatch(\r\n addNotification(\r\n \"The NAT files have been successfully uploaded.\",\r\n \"info\"\r\n )\r\n );\r\n })\r\n .catch((err) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_IMPORT_FAILURE,\r\n });\r\n dispatch(\r\n addNotification(\"There was an issue importing the NAT files.\", \"error\")\r\n );\r\n });\r\n};\r\n\r\nexport const exportNatFiles = () => async (dispatch) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_EXPORT_REQUEST,\r\n });\r\n\r\n const service = AvetmissReportingSubmissionService();\r\n\r\n await service\r\n .exportNatFiles()\r\n .then((resp) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_EXPORT_SUCCESS,\r\n });\r\n\r\n const { data, headers } = resp;\r\n\r\n if (!data) {\r\n throw Error(\"Unable to export the NAT files.\");\r\n }\r\n\r\n let file = new Blob([data], {\r\n type: headers[\"content-type\"],\r\n });\r\n\r\n saveAs(file, parse(headers[\"content-disposition\"]).parameters.filename);\r\n\r\n dispatch(\r\n addNotification(\r\n \"The NAT files have been successfully exported.\",\r\n \"info\"\r\n )\r\n );\r\n })\r\n .catch((err) => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_SUBMISSION_EXPORT_FAILURE,\r\n });\r\n dispatch(\r\n addNotification(\"There was an issue exporting the NAT files.\", \"error\")\r\n );\r\n });\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport AvetmissReportingSubmission from \"./avetmiss-reporting-submission\";\r\nimport { selectAvetmissReportingSubmission } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const avetmissReportingSubmission = selectAvetmissReportingSubmission(state);\r\n\r\n return {\r\n avetmissReportingSubmission: avetmissReportingSubmission,\r\n isLoading: avetmissReportingSubmission.isLoading,\r\n isDeleting: avetmissReportingSubmission.isDeleting,\r\n isImporting: avetmissReportingSubmission.isImporting,\r\n showDeleteDialog: avetmissReportingSubmission.showDeleteDialog,\r\n showImportDialog: avetmissReportingSubmission.showImportDialog,\r\n isExporting: avetmissReportingSubmission.isExporting,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n // onInputChange: ({ name, value, error }) => {\r\n // dispatch(actionCreators.formInputChange(name, value, error));\r\n // },\r\n toggleDeleteDialog: () => dispatch(actionCreators.toggleDeleteDialog()),\r\n toggleImportDialog: () => dispatch(actionCreators.toggleImportDialog()),\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadForm: () => {\r\n dispatchProps.dispatch(actionCreators.onLoadForm(dispatchProps.history));\r\n },\r\n onSubmit: (\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state\r\n ) => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmit(\r\n year,\r\n period,\r\n version,\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n dispatchProps.history\r\n )\r\n );\r\n },\r\n onDelete: () => {\r\n dispatchProps.dispatch(actionCreators.onDelete(dispatchProps.history));\r\n },\r\n onImport: async (payload) => {\r\n dispatchProps.dispatch(actionCreators.importNatFiles(payload));\r\n },\r\n validate: () => {\r\n return validate(stateProps);\r\n },\r\n exportNatFiles: () => {\r\n dispatchProps.dispatch(actionCreators.exportNatFiles());\r\n },\r\n});\r\n\r\nconst validate = stateProps => {\r\n const fields = stateProps.fields;\r\n const fieldErrors = stateProps.fieldErrors;\r\n const errMessages = Object.keys(fieldErrors).filter(k => fieldErrors[k]);\r\n\r\n if (!fields.year) return true;\r\n if (!fields.period) return true;\r\n if (!fields.version) return true;\r\n if (errMessages.length > 0) return true;\r\n\r\n return false;\r\n};\r\n\r\nconst AvetmissReportingSubmissionContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(AvetmissReportingSubmission);\r\n\r\nexport default AvetmissReportingSubmissionContainer;\r\n","import React from \"react\";\r\nimport TextAreaField from \"../../../../components/Common/Fields/Text-Area-Field\";\r\n\r\nconst ValidationError = ({\r\n natFileNumber,\r\n fileId,\r\n recordNumber,\r\n errorMessage,\r\n fieldValue,\r\n onInputChange\r\n}) => {\r\n return (\r\n \r\n \r\n {fileId} ({recordNumber})\r\n \r\n {errorMessage} \r\n \r\n cardNameValidator(\"Card Name\", val)}\r\n rows={10}\r\n />\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ValidationError;\r\n","import React, { Component } from \"react\";\r\nimport { Modal, ModalHeader, ModalBody, ModalFooter } from \"reactstrap\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\n\r\nexport default class EditUserModal extends Component {\r\n render() {\r\n const {\r\n toggleDeleteDialog,\r\n showDeleteDialog,\r\n isDeleting,\r\n onDelete\r\n } = this.props;\r\n return (\r\n \r\n \r\n toggleDeleteDialog()}>\r\n Delete NAT Files\r\n \r\n \r\n \r\n Are you sure you are ready to delete the NAT files?\r\n \r\n \r\n \r\n onDelete()}\r\n className=\"ttg-btn\"\r\n isLoading={isDeleting}\r\n >\r\n Delete\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n","import React, { Component } from \"react\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport ValidationError from \"./sub-views/validation-error\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport DeleteDialog from \"./delete-dialog\";\r\nimport \"./avetmiss-reporting-validation.scss\";\r\n\r\nclass AvetmissReportingValidation extends Component {\r\n componentDidMount() {\r\n const { hasResult, onLoadForm } = this.props;\r\n\r\n if (!hasResult) onLoadForm();\r\n }\r\n\r\n render() {\r\n const { verificationResult } = this.props.avetmissReportingValidation;\r\n const {\r\n isLoading,\r\n isDownloading,\r\n isDeleting,\r\n toggleDeleteDialog,\r\n showDeleteDialog,\r\n onDelete,\r\n onDownloadNatFiles,\r\n onInputChange,\r\n onSubmit,\r\n } = this.props;\r\n\r\n return (\r\n <>\r\n \r\n \r\n Avetmiss Validation Service | Validation \r\n \r\n \r\n {verificationResult.verificationSuccessful && (\r\n <>\r\n Avetmiss Reporting Validated Successfully \r\n Step 1 \r\n \r\n Please login to the{\" \"}\r\n \r\n AVETMISS Validation Software\r\n {\" \"}\r\n to finalise your submission. Once you login, click the latest\r\n submission under Collections and then press “Finalise\r\n Submission”.\r\n
\r\n Step 2 \r\n \r\n onDownloadNatFiles()}\r\n >\r\n Download NAT Files\r\n \r\n
\r\n Step 3 \r\n \r\n toggleDeleteDialog()}\r\n >\r\n Delete NAT Files\r\n \r\n
\r\n \r\n >\r\n )}\r\n {!verificationResult.verificationSuccessful && (\r\n <>\r\n \r\n \r\n {verificationResult.errors.map((error, i) => (\r\n \r\n ))}\r\n \r\n
\r\n onSubmit(verificationResult.errors)}\r\n >\r\n Save Changes\r\n \r\n >\r\n )}\r\n \r\n >\r\n );\r\n }\r\n}\r\n\r\nexport default AvetmissReportingValidation;\r\n","/**\r\n * Avetmiss Reporting Validation Service\r\n */\r\nimport HttpClient from \"../../../coreLib/http/httpClient\";\r\n\r\nconst AvetmissReportingValidationService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getStatus = () => {\r\n return httpClient.get(\"/v1/avetmiss/status\");\r\n };\r\n\r\n const submitRequest = payload => {\r\n return httpClient.put(\"/v1/avetmiss/validation/update\", payload);\r\n };\r\n\r\n const deleteRequest = payload => {\r\n return httpClient.delete(\"/v1/avetmiss\");\r\n };\r\n\r\n const downloadNatFiles = () => {\r\n return httpClient.get(\"/v1/avetmiss/download\", {\r\n responseType: \"blob\"\r\n });\r\n };\r\n\r\n return {\r\n getStatus,\r\n submitRequest,\r\n deleteRequest,\r\n downloadNatFiles\r\n };\r\n};\r\n\r\nexport default AvetmissReportingValidationService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport AvetmissReportingValidationService from \"../avetmiss-reporting-validation-service\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\nexport const onLoadForm = history => {\r\n return dispatch => {\r\n dispatch(LoadFormRequest());\r\n\r\n const service = AvetmissReportingValidationService();\r\n\r\n service\r\n .getStatus()\r\n .then(resp => {\r\n dispatch(LoadFormSuccess());\r\n\r\n if (!resp.data.validToken) {\r\n history.push(\"/Admin/Avetmiss/Authorise/\");\r\n return;\r\n }\r\n\r\n if (\r\n resp.status !== 204 &&\r\n resp.data.reports !== null &&\r\n resp.data.reports !== [] &&\r\n resp.data.reports.length > 0\r\n ) {\r\n history.push(\"/Admin/Avetmiss/Submission/\");\r\n return;\r\n } else {\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n return;\r\n }\r\n })\r\n .catch(err => {\r\n dispatch(LoadFormFailure());\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n });\r\n };\r\n};\r\n\r\nconst LoadFormRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_LOAD_FORM_REQUEST\r\n});\r\n\r\nconst LoadFormSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_LOAD_FORM_SUCCESS\r\n});\r\n\r\nconst LoadFormFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_LOAD_FORM_FAILURE\r\n});\r\n\r\n// Async\r\nexport const onSubmit = (errors, history) => dispatch => {\r\n dispatch(onSubmitRequest());\r\n\r\n const service = AvetmissReportingValidationService();\r\n\r\n const model = errors\r\n .filter(x => x.updated)\r\n .map(error => ({\r\n natFileNumber: error.natFileNumber,\r\n version: error.version,\r\n fileId: error.fileId,\r\n recordNumber: error.recordNumber,\r\n fieldValue: error.fieldValue\r\n }));\r\n\r\n if (model.length > 0) {\r\n service\r\n .submitRequest(model)\r\n .then(resp => {\r\n dispatch(onSubmitSuccess());\r\n dispatch(addNotification(\"Changes saved.\", \"info\"));\r\n history.push(\"/Admin/Avetmiss/Submission/\");\r\n })\r\n .catch(err => {\r\n dispatch(onSubmitFailure());\r\n dispatch(\r\n addNotification(\"There was an issue updating the NAT files.\", \"error\")\r\n );\r\n });\r\n } else {\r\n dispatch(onSubmitFailure());\r\n dispatch(addNotification(\"No changes have been detected.\", \"error\"));\r\n }\r\n};\r\n\r\nconst onSubmitRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_SUBMIT_REQUEST\r\n});\r\nconst onSubmitSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_SUBMIT_SUCCESS\r\n});\r\nconst onSubmitFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_SUBMIT_FAILURE\r\n});\r\n\r\nexport const onDelete = history => dispatch => {\r\n dispatch(onDeleteRequest());\r\n\r\n const service = AvetmissReportingValidationService();\r\n\r\n service\r\n .deleteRequest()\r\n .then(resp => {\r\n dispatch(onDeleteSuccess());\r\n history.push(\"/Admin/Avetmiss/Reporting/\");\r\n })\r\n .catch(err => {\r\n dispatch(onDeleteFailure());\r\n dispatch(\r\n addNotification(\"There was an issue deleting the NAT files.\", \"error\")\r\n );\r\n });\r\n};\r\n\r\nconst onDeleteRequest = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DELETE_REQUEST\r\n});\r\nconst onDeleteSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DELETE_SUCCESS\r\n});\r\nconst onDeleteFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DELETE_FAILURE\r\n});\r\n\r\nexport const toggleDeleteDialog = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_SHOW_DELETE_DIALOG\r\n });\r\n};\r\n\r\nexport const onDownloadNatFiles = () => dispatch => {\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DOWNLOAD_NAT_FILES_REQUEST\r\n });\r\n let service = AvetmissReportingValidationService();\r\n service\r\n .downloadNatFiles()\r\n .then(resp => {\r\n dispatch(onDownloadNatFilesSuccess());\r\n const pdfBlob = new Blob([resp.data], { type: \"application/zip\" });\r\n saveAs(pdfBlob, \"natfiles.zip\");\r\n })\r\n .catch(() => {\r\n dispatch(onDownloadNatFilesFailure());\r\n dispatch(addNotification(\"Unable to the NAT files.\", \"error\"));\r\n });\r\n};\r\n\r\nconst onDownloadNatFilesSuccess = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DOWNLOAD_NAT_FILES_SUCCESS\r\n});\r\n\r\nconst onDownloadNatFilesFailure = () => ({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_DOWNLOAD_NAT_FILES_FAILURE\r\n});\r\n\r\n// ----------------------------\r\n// Form Actions\r\n// ----------------------------\r\n\r\nexport const formInputChange = (name, value, error) => {\r\n return dispatch => {\r\n const natFileNumber = parseInt(name.match(/(\\d+)-/im)[1]);\r\n const recordNumber = parseInt(name.match(/-(\\d+)/im)[1]);\r\n\r\n dispatch({\r\n type: ActionTypes.AVETMISS_REPORTING_VALIDATION_FORM_INPUT_CHANGE,\r\n payload: {\r\n natFileNumber: natFileNumber,\r\n recordNumber: recordNumber,\r\n fieldValue: value\r\n }\r\n });\r\n };\r\n};\r\n","import { connect } from \"react-redux\";\r\nimport AvetmissReportingValidation from \"./avetmiss-reporting-validation\";\r\nimport { selectAvetmissReportingValidation } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\n\r\nfunction mapStateToProps(state) {\r\n const avetmissReportingValidation = selectAvetmissReportingValidation(state);\r\n\r\n return {\r\n isLoading: avetmissReportingValidation.isLoading,\r\n isDownloading: avetmissReportingValidation.isDownloading,\r\n isDeleting: avetmissReportingValidation.isDeleting,\r\n showDeleteDialog: avetmissReportingValidation.showDeleteDialog,\r\n hasResult: avetmissReportingValidation.hasResult,\r\n avetmissReportingValidation: avetmissReportingValidation\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n onInputChange: ({ name, value, error }) => {\r\n dispatch(actionCreators.formInputChange(name, value, error));\r\n },\r\n toggleDeleteDialog: () => dispatch(actionCreators.toggleDeleteDialog()),\r\n onDownloadNatFiles: () => dispatch(actionCreators.onDownloadNatFiles()),\r\n dispatch: dispatch,\r\n history: ownProps.history\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadForm: () => {\r\n dispatchProps.dispatch(actionCreators.onLoadForm(dispatchProps.history));\r\n },\r\n onSubmit: errors => {\r\n dispatchProps.dispatch(\r\n actionCreators.onSubmit(errors, dispatchProps.history)\r\n );\r\n },\r\n onDelete: () => {\r\n dispatchProps.dispatch(actionCreators.onDelete(dispatchProps.history));\r\n }\r\n});\r\n\r\nconst AvetmissReportingValidationContainer = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(AvetmissReportingValidation);\r\n\r\nexport default AvetmissReportingValidationContainer;\r\n","import React from \"react\";\r\nimport TextAreaField from \"../../../../components/Common/Fields/Text-Area-Field\";\r\n\r\nconst ValidationError = ({\r\n natFileNumber,\r\n fileId,\r\n recordNumber,\r\n errorMessage,\r\n fieldValue,\r\n onInputChange,\r\n}) => {\r\n return (\r\n \r\n \r\n {fileId} ({recordNumber})\r\n \r\n {errorMessage} \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default ValidationError;\r\n","import HttpClient from \"../../../../coreLib/http/httpClient\";\r\n\r\nconst ApiService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const submitChanges = (payload) => {\r\n return httpClient.post(\"/v1/avetmiss/validation/address-fixes\", payload);\r\n };\r\n\r\n return {\r\n submitChanges,\r\n };\r\n};\r\n\r\nexport default ApiService;\r\n","import moment from \"moment\";\r\nimport { addNotification } from \"../../../../redux/system/system-action-creators\";\r\nimport ApiService from \"../services/api-service\";\r\nimport { ActionTypes } from \"./action-types\";\r\n\r\nexport const formInputChange = (name, value, error) => (dispatch) => {\r\n const natFileNumber = parseInt(name.match(/(\\d+)-/im)[1]);\r\n const recordNumber = parseInt(name.match(/-(\\d+)/im)[1]);\r\n\r\n dispatch({\r\n type: ActionTypes.AVETMISS_ADDRESS_VALIDATION_FORM_INPUT_CHANGE,\r\n payload: {\r\n natFileNumber: natFileNumber,\r\n recordNumber: recordNumber,\r\n fieldValue: value,\r\n },\r\n });\r\n};\r\n\r\nexport const submitChanges = (\r\n collectionStartDate,\r\n collectionEndDate,\r\n state,\r\n version,\r\n year,\r\n period,\r\n errors,\r\n history\r\n) => (dispatch) => {\r\n dispatch(submitChangesRequest());\r\n\r\n const service = ApiService();\r\n\r\n const fixes = errors\r\n .filter((x) => x.updated)\r\n .map((error) => ({\r\n natFileNumber: error.natFileNumber,\r\n version: error.version,\r\n fileId: error.fileId,\r\n recordNumber: error.recordNumber,\r\n fieldValue: error.fieldValue,\r\n }));\r\n\r\n const formatDateToYYYYMMDD = (date) => {\r\n const isDDMMYYYY = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/.test(date);\r\n\r\n return isDDMMYYYY ? moment(date, \"DD/MM/YYYY\").format(\"YYYY-MM-DD\") : date;\r\n };\r\n\r\n const payload = {\r\n collectionStartDate: formatDateToYYYYMMDD(collectionStartDate),\r\n collectionEndDate: formatDateToYYYYMMDD(collectionEndDate),\r\n state: state,\r\n version: version,\r\n year: year,\r\n period: period,\r\n fixes: fixes,\r\n };\r\n\r\n if (fixes.length > 0) {\r\n service\r\n .submitChanges(payload)\r\n .then((resp) => {\r\n dispatch(submitChangesSuccess());\r\n dispatch(addNotification(\"Changes saved.\", \"info\"));\r\n\r\n dispatch({\r\n type: \"AVETMISS_REPORTING_SUBMISSION_LOAD_FORM_SUCCESS\",\r\n payload: {\r\n files: resp.data.reports,\r\n year: resp.data.year,\r\n period: resp.data.period,\r\n version: resp.data.version,\r\n collectionStartDate: collectionStartDate,\r\n collectionEndDate: collectionEndDate,\r\n state: state,\r\n },\r\n });\r\n\r\n history.push(\"/Admin/Avetmiss/Submission/\");\r\n })\r\n .catch((err) => {\r\n dispatch(submitChangesFailure());\r\n dispatch(\r\n addNotification(\r\n \"There was an issue applying address validation error fixes.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n\r\n return;\r\n }\r\n\r\n dispatch(submitChangesFailure());\r\n dispatch(addNotification(\"No changes have been detected.\", \"error\"));\r\n};\r\n\r\nconst submitChangesRequest = () => ({\r\n type: ActionTypes.AVETMISS_ADDRESS_VALIDATION_SUBMIT_REQUEST,\r\n});\r\nconst submitChangesSuccess = () => ({\r\n type: ActionTypes.AVETMISS_ADDRESS_VALIDATION_SUBMIT_SUCCESS,\r\n});\r\nconst submitChangesFailure = () => ({\r\n type: ActionTypes.AVETMISS_ADDRESS_VALIDATION_SUBMIT_FAILURE,\r\n});\r\n","import React, { useState } from \"react\";\r\nimport { useDispatch, useSelector } from \"react-redux\";\r\nimport { useHistory } from \"react-router\";\r\nimport ButtonFx from \"../../../components/Common/Button-Fx/Button-Fx\";\r\nimport PageTitle from \"../../../components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"../../../components/Content-Section\";\r\nimport ValidationError from \"./components/validation-error\";\r\nimport * as Selectors from \"./redux/reducer\";\r\nimport * as Actions from \"./redux/action-creators\";\r\nimport \"./style.scss\";\r\n\r\nconst AvetmissAddressValidation = () => {\r\n const addressValidationState = useSelector((state) =>\r\n Selectors.selectAvetmissAddressValidation(state)\r\n );\r\n\r\n const history = useHistory();\r\n const dispatch = useDispatch();\r\n\r\n useState(() => {\r\n let hasNoAddressErrors = !addressValidationState.verificationResult\r\n .addressErrors?.length;\r\n\r\n if (hasNoAddressErrors) {\r\n history.push(\"/Admin/Avetmiss/Validation/\");\r\n }\r\n }, []);\r\n\r\n const onSubmit = async (errors) => {\r\n dispatch(\r\n Actions.submitChanges(\r\n addressValidationState.collectionStartDate,\r\n addressValidationState.collectionEndDate,\r\n addressValidationState.state,\r\n addressValidationState.version,\r\n addressValidationState.year,\r\n addressValidationState.period,\r\n errors,\r\n history\r\n )\r\n );\r\n };\r\n\r\n const onInputChange = async ({ name, value, error }) => {\r\n dispatch(Actions.formInputChange(name, value, error));\r\n };\r\n\r\n return (\r\n <>\r\n \r\n \r\n Avetmiss Validation Service | Address \r\n \r\n State identifiers \r\n \r\n NSW: 01\r\n \r\n VIC: 02\r\n \r\n QLD: 03\r\n \r\n SA: 04\r\n \r\n WA: 05\r\n \r\n TAS: 06\r\n \r\n NT: 07\r\n \r\n ACT: 08\r\n
\r\n \r\n \r\n {!addressValidationState.verificationResult.verificationSuccessful && (\r\n <>\r\n \r\n \r\n {addressValidationState.verificationResult.addressErrors.map(\r\n (error, i) => (\r\n \r\n )\r\n )}\r\n \r\n
\r\n \r\n onSubmit(\r\n addressValidationState.verificationResult.addressErrors\r\n )\r\n }\r\n >\r\n Save Changes\r\n \r\n >\r\n )}\r\n \r\n >\r\n );\r\n};\r\n\r\nexport default AvetmissAddressValidation;\r\n","import HttpClient from \"coreLib/http/httpClient\";\r\n\r\nconst ApiService = () => {\r\n const syncApiRootUrl = \"v1/sync\";\r\n const courseApiRootUrl = \"v1/courses\";\r\n\r\n const syncCoursesFromElearnd = () => {\r\n return HttpClient().post(`${syncApiRootUrl}/elearnd-courses`);\r\n };\r\n\r\n const publishCourse = (courseId) => {\r\n return HttpClient().post(`${courseApiRootUrl}/${courseId}/publish`);\r\n };\r\n\r\n return {\r\n syncCoursesFromElearnd,\r\n publishCourse,\r\n };\r\n};\r\n\r\nexport default ApiService;\r\n","import ActionTypes from \"./action-types\";\r\nimport ApiService from \"../services/api-service\";\r\nimport {\r\n addErrorNotification,\r\n addNotification,\r\n} from \"redux/system/system-action-creators\";\r\n\r\nconst operateRequest = () => ({\r\n type: ActionTypes.SYNC_COURSES_OPERATE_REQUEST,\r\n});\r\n\r\nconst operateFailure = () => ({\r\n type: ActionTypes.SYNC_COURSES_OPERATE_FAILURE,\r\n});\r\n\r\nconst syncCourseRequest = (payload) => ({\r\n type: ActionTypes.SYNC_COURSES_SYNC_REQUEST,\r\n payload,\r\n});\r\n\r\nconst syncCourseSuccess = (payload) => ({\r\n type: ActionTypes.SYNC_COURSES_SYNC_SUCCESS,\r\n payload,\r\n});\r\n\r\nconst publishCourseSuccess = () => ({\r\n type: ActionTypes.SYNC_COURSES_PUBLISH_SUCCESS,\r\n});\r\n\r\nexport const syncCoursesFromElearnd = () => async (dispatch) => {\r\n dispatch(syncCourseRequest());\r\n\r\n const apiService = ApiService();\r\n\r\n return await apiService\r\n .syncCoursesFromElearnd()\r\n .then((resp) => {\r\n if (resp.data.isSuccessful) {\r\n dispatch(syncCourseSuccess(resp.data.syncedCourses));\r\n dispatch(addNotification(\"Successfully synced courses from eLearnd.\"));\r\n\r\n return {\r\n isSuccessful: true,\r\n };\r\n }\r\n\r\n dispatch(operateFailure());\r\n return {\r\n isSuccessful: false,\r\n validationMessages: resp.data.validationMessages,\r\n };\r\n })\r\n .catch((error) => {\r\n dispatch(operateFailure());\r\n dispatch(\r\n addErrorNotification(\r\n error,\r\n \"Sorry, unable to sync courses from eLearnd.\"\r\n )\r\n );\r\n });\r\n};\r\n\r\nexport const publishCourse = (courseId) => async (dispatch) => {\r\n dispatch(operateRequest());\r\n\r\n const apiService = ApiService();\r\n\r\n await apiService\r\n .publishCourse(courseId)\r\n .then((resp) => {\r\n dispatch(addNotification(\"Successfully published course.\"));\r\n dispatch(publishCourseSuccess());\r\n dispatch(syncCoursesFromElearnd());\r\n })\r\n .catch((error) => {\r\n dispatch(operateFailure());\r\n dispatch(addErrorNotification(error, \"Sorry, unable to publish course.\"));\r\n });\r\n};\r\n","import React, { useEffect } from \"react\";\r\nimport { Button, Spinner, Table } from \"reactstrap\";\r\nimport \"./sync-view.scss\";\r\nimport PageTitle from \"components/Common/Page-Title/Page-Title\";\r\nimport ContentSection from \"components/Content-Section\";\r\nimport { useDispatch, useSelector } from \"react-redux\";\r\nimport * as Actions from \"./redux/action-creators\";\r\nimport BlockUiFx from \"components/Common/Block-Ui-Fx/Block-Ui-Fx\";\r\nimport { useState } from \"react\";\r\nimport ConfirmModal from \"components/Common/Confirm-Modal/Confirm-Modal\";\r\nimport BasicModal from \"components/Common/Basic-Modal/Basic-Modal\";\r\n\r\nconst SyncView = () => {\r\n const dispatch = useDispatch();\r\n\r\n const selectSyncCourses = useSelector((state) => state.syncCourses);\r\n const [showValidationDialog, toggleValidationDialog] = useState(false);\r\n const [validationMessages, setValidationMessages] = useState(null);\r\n\r\n const [\r\n showPublishConfirmationDialog,\r\n togglePublishConfirmationDialog,\r\n ] = useState(false);\r\n\r\n const [selectedCourseId, setSelectedCourseId] = useState(null);\r\n\r\n useEffect(() => {\r\n dispatch(Actions.syncCoursesFromElearnd()).then((resp) => {\r\n if (!resp.isSuccessful) {\r\n setValidationMessages(resp.validationMessages);\r\n toggleValidationDialog(true);\r\n }\r\n });\r\n }, []);\r\n\r\n const handleOnPublishConfirmation = (evt) => {\r\n if (evt.type !== \"ok\") {\r\n togglePublishConfirmationDialog(false);\r\n return;\r\n }\r\n\r\n dispatch(Actions.publishCourse(selectedCourseId));\r\n togglePublishConfirmationDialog(false);\r\n };\r\n\r\n return (\r\n <>\r\n \r\n \r\n Content Sync \r\n \r\n \r\n \r\n Are you sure you wish to publish the new content now? Note: this\r\n cannot be undone.\r\n \r\n\r\n toggleValidationDialog(false)}\r\n okButtonText={\"Ok\"}\r\n showCancel={false}\r\n >\r\n Sorry, failed to sync courses from eLearnd. \r\n {validationMessages && (\r\n \r\n
Please check the following: \r\n
\r\n {validationMessages.map((msg, index) => (\r\n {msg} \r\n ))}\r\n \r\n
\r\n )}\r\n \r\n\r\n \r\n {selectSyncCourses.isSyncing && (\r\n \r\n \r\n \r\n Syncing with eLearnd, please wait.\r\n \r\n
\r\n )}\r\n {!selectSyncCourses.isSyncing && (\r\n \r\n \r\n \r\n Course \r\n CSC \r\n Last Published \r\n Status \r\n \r\n \r\n \r\n \r\n {selectSyncCourses.courses.map((course, i) => (\r\n \r\n \r\n {course.courseTitle} \r\n ({course.certificateCodesString})\r\n \r\n {course.currentSetCount} \r\n {course.publishDateTime} \r\n \r\n {course.isWaitingPublishing\r\n ? \"Waiting Publishing\"\r\n : \"Synced\"}\r\n \r\n \r\n {course.isWaitingPublishing && (\r\n {\r\n setSelectedCourseId(course.courseId);\r\n togglePublishConfirmationDialog(true);\r\n }}\r\n disabled={selectSyncCourses.isLoading}\r\n >\r\n Publish Now\r\n \r\n )}\r\n \r\n \r\n ))}\r\n \r\n
\r\n )}\r\n \r\n \r\n >\r\n );\r\n};\r\n\r\nexport default SyncView;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst NswFoodSafetySupervisorCertificate = () => {\r\n return (\r\n <>\r\n \r\n \r\n This Food Safety Supervisor course prepares you with an\r\n extensive understanding of the role of a Food Safety\r\n Supervisor in NSW.\r\n
\r\n \r\n Owners of registered food businesses must ensure those who\r\n handle food within their business handle food safely. The\r\n owner must nominate a Food Safety Supervisor, who has the\r\n responsibility of recognising, preventing and alleviating the\r\n hazards associated with food handling in your business. Under{\" \"}\r\n FSANZ Standard 3.2.2A , all Australian\r\n businesses that serve food must have one or more qualified\r\n Food Safety Supervisor. A Food Safety Supervisor is someone\r\n who has the appropriate Food Safety training to supervise Food\r\n Safety in a business. Food Safety Supervisors are mainly\r\n responsible for:\r\n
\r\n \r\n Supervising Food Handling staff \r\n Maintaining the Food Safety Program \r\n \r\n Ensuring safe food handling practices across the business\r\n \r\n \r\n \r\n All retail, hospitality and food service businesses need to\r\n appoint at least one Food Safety Supervisor (FSS) per premises\r\n if food they prepare and serve is:\r\n
\r\n \r\n Ready-to-eat. \r\n \r\n Potentially hazardous, that is, needs temperature control.\r\n \r\n \r\n NOT sold and served in the supplier's original package.\r\n \r\n \r\n\r\n \r\n Broadly, this includes all businesses selling potentially\r\n hazardous food to the public that are not{\" \"}\r\n \r\n licensed\r\n {\" \"}\r\n by the Food Authority, such as: cafes, restaurants, quick\r\n service venues, takeaway shops, pubs and clubs with food\r\n service areas, mobile vendors, home-based businesses,\r\n caterers, motels, and supermarkets selling potentially\r\n hazardous food (such as hot-chickens). It also includes\r\n outlets that sell food through third party ordering apps.\r\n
\r\n \r\n Children’s services that provide meals as part of their\r\n operation now are required to comply with new Food Safety\r\n requirements, introduced under Standard 3.2.2A of the Food\r\n Standards Code.\r\n
\r\n \r\n \r\n Click here for the Food Safety requirements for\r\n children’s services in NSW.\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I get my certificate?\",\r\n content: (\r\n <>\r\n \r\n It's as easy as following these 3 steps for the quickest,\r\n cheapest and most convenient way to get your NSW Food Safety\r\n Supervisor Certificate:\r\n
\r\n \r\n Select the NSW $179 Food Safety Supervisor Course. \r\n \r\n Make payment and enter the postal address where your NSW\r\n Food Safety Supervisor Certificate will be express posted.\r\n \r\n Begin enrolment and complete online course. \r\n \r\n Total course fee: $179
\r\n \r\n With Food Safety Education there are no hidden fees or\r\n charges.\r\n
\r\n \r\n Upon completion of the course, you will receive the NSW Food\r\n Safety Supervisor Certificate (HARD COPY) this will be\r\n expressed posted to you PLUS a Nationally Accredited Statement\r\n of Attainment that is recognised in every other State of\r\n Australia, which you can download straight away!\r\n
\r\n That’s right you will get two certificates!
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Breakdown of Costs\",\r\n content: (\r\n <>\r\n \r\n \r\n $139 Nationally Accredited Certificate - This can be\r\n downloaded automatically on the successful completion of\r\n your course.\r\n \r\n \r\n $30 NSW Food Safety Supervisor Certificate - This is what\r\n the NSW Food Authority charge us!\r\n \r\n \r\n $10 Express Postage, Administration & Handling. This ensures\r\n you will receive your certificate within 5 to 7 business\r\n days via express post after you have successfully completed\r\n the course.\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Which category does my food business comply with?\",\r\n content: (\r\n <>\r\n \r\n Food service, catering and retail businesses must comply with\r\n Standard 3.2.2A, based on whether they are classified as\r\n category one or category two businesses (see below).\r\n
\r\n \r\n \r\n Category one (higher risk) businesses must implement all\r\n three management tools.\r\n \r\n \r\n Category two businesses must have a Food Safety Supervisor\r\n and trained food handlers.\r\n \r\n \r\n \r\n These requirements are in place because unpackaged,\r\n potentially hazardous food that is ready to eat is high risk\r\n and needs careful handling to keep it safe.\r\n
\r\n\r\n \r\n Category one business \r\n
\r\n \r\n \r\n A caterer or food service business that processes unpackaged\r\n potentially hazardous food into food that is both\r\n ready-to-eat and potentially hazardous food.\r\n \r\n \r\n The food is then served to a consumer to eat without any\r\n further processing.\r\n \r\n \r\n \r\n Category two business \r\n
\r\n \r\n \r\n A retailer of potentially hazardous, ready-to-eat food,\r\n where the food was handled unpackaged, but not made or\r\n processed onsite (other than slicing, weighing, repacking,\r\n reheating, or hot-holding).\r\n \r\n \r\n \r\n Sometimes it can be confusing to know which category your food\r\n business falls under. We suggest talking with the NSW Food\r\n Authority before you commence your training if you are unsure.\r\n
\r\n\r\n \r\n PH: 1300 552 406 \r\n
\r\n \r\n Please click on this link below for more information on\r\n Standard 3.2.2 A, this is very useful.\r\n
\r\n \r\n \r\n https://www.foodauthority.nsw.gov.au/retail/standard-322a-food-safety-management-tools/standard-322a-frequently-asked-questions\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n The current national units of competency we deliver and are\r\n accepted for the NSW Food Safety Supervisor Certificate are:\r\n
\r\n \r\n Two hospitality units: \r\n
\r\n \r\n SITXFSA005 – Use hygiene practices for food safety \r\n \r\n SITXFSA006 – Participate in safe food handling practices\r\n \r\n \r\n \r\n The units of competency we deliver incorporate the mandatory 4\r\n key focus areas as determined by the NSW Food Authority. The\r\n key focus areas were developed in response to common high risk\r\n Food Safety issues in the retail and hospitality sectors and\r\n include:\r\n
\r\n \r\n Allergen Management \r\n Cleaning and Sanitising Practices \r\n Safe Egg Handling \r\n Food Act Offences \r\n \r\n \r\n This Food Safety Supervisor course prepares you with an\r\n extensive understanding of the role a Food Safety Supervisor\r\n must play within the workplace. Our course is designed to be\r\n as flexible and straight forward as possible! We pride\r\n ourselves on our learning platform which is filled with many\r\n short DVD's and visual images making this training course a\r\n fast and effective way to obtain your Nationally Accredited\r\n Certificate.\r\n
\r\n \r\n Open text responses are required to answer some questions and\r\n case studies from the key focus areas and a third party form\r\n needs to be completed from your nominated observer.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lock outs\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Safety Supervisor training, we also\r\n offer you a downloadable course workbook. This online course\r\n material is always updated so we encourage you to log back in\r\n any time after your training and obtain any new Food Safety\r\n information, this is especially helpful when training up new\r\n staff and when council come around!\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"NSW Food Authority Information\",\r\n content: (\r\n <>\r\n \r\n You will need to ensure that the NSW Food Safety Supervisor\r\n certificate is always kept on the premises, as council\r\n inspectors may request to view the certificate during an\r\n inspection.\r\n
\r\n \r\n For further Food Safety Supervisor information please{\" \"}\r\n \r\n click here\r\n \r\n .\r\n
\r\n \r\n Email:{\" \"}\r\n \r\n contact@foodauthority.nsw.gov.au\r\n \r\n \r\n Phone:{\" \"}\r\n \r\n 1300 552 406 \r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default NswFoodSafetySupervisorCertificate;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst NswFoodSafetySupervisorCertificateRefresher = () => {\r\n return (\r\n <>\r\n \r\n \r\n The NSW Food Authority Refresher Course Training is an\r\n essential program for individuals in New South Wales (NSW),\r\n Australia, who work in the food industry. This online training\r\n ensures that food handlers and supervisors maintain up-to-date\r\n knowledge of safe food handling practices and comply with\r\n legal requirements.{\" \"}\r\n \r\n Please click here for more information about the NSW Food\r\n Safety Refresher Course.\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Purpose of the Refresher Training\",\r\n content: (\r\n <>\r\n \r\n \r\n Compliance with Regulations: The course aligns with the\r\n requirements of the{\" \"}\r\n NSW Food Act 2003 and Food Standards Code . It is\r\n particularly aimed at Food Safety Supervisors (FSS) who are\r\n required to renew their certification every five years.\r\n \r\n \r\n Updated Knowledge: It helps participants stay informed about\r\n the latest changes in food safety laws, practices, and\r\n industry standards.\r\n \r\n \r\n Public Health Protection: By ensuring best practices, the\r\n course reduces risks of foodborne illnesses, safeguarding\r\n consumer health.\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"How do I Renew?\",\r\n content: (\r\n <>\r\n \r\n If you already have a NSW Food Safety Supervisor Certificate\r\n you can renew it with us online today!\r\n
\r\n \r\n Simply \r\n
\r\n \r\n \r\n Simply Log back in (top right) of the website or re register\r\n if you have updated your details.\r\n \r\n \r\n Select the NSW Refresher Course option and begin your\r\n training.\r\n \r\n \r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default NswFoodSafetySupervisorCertificateRefresher;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst FoodSafetySupervisorCertificateHospitalityAndRetail = () => {\r\n return (\r\n <>\r\n \r\n \r\n When you enrol with us, you have access to everything you need\r\n to be accredited as a qualified Food Safety Supervisor (FSS)\r\n in Australia.{\" \"}\r\n \r\n If you are a business in NSW please do the NSW specific\r\n training. Not this one!\r\n \r\n
\r\n \r\n Under FSANZ Standard 3.2.2A, all Australian businesses that\r\n serve food must have one or more qualified Food Safety\r\n Supervisor. A Food Safety Supervisor is someone who has the\r\n appropriate Food Safety training to supervise Food Safety in a\r\n business. Food Safety Supervisors are mainly responsible for:\r\n
\r\n \r\n Supervising Food Handling Staff \r\n Maintaining the Food Safety Program \r\n \r\n Ensuring Safe Food Handling Practices across the business\r\n \r\n \r\n \r\n The new requirements outlined in FSANZ Standard 3.2.2A demand\r\n a higher level of compliance compared to previous regulations.\r\n Failure to comply can have serious consequences. Enforcement\r\n begins in December 2023 and is overseen by local governments.\r\n
\r\n \r\n Penalties for non-compliance vary based on the severity of\r\n violations and potentially leading to fines, license\r\n suspension or even revocation.\r\n
\r\n \r\n Owners of registered food businesses must ensure those who\r\n handle food within their business handle food safely. The\r\n owner must nominate a Food Safety Supervisor, who has the\r\n responsibility of recognising, preventing and alleviating the\r\n hazards associated with food handling in your business.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Is this course for me?\",\r\n content: (\r\n <>\r\n \r\n Either way, it is a requirement that a Food Safety Supervisor\r\n is appointed to the food business. Depending on how large the\r\n food operation is, or how available the FSS can be, will vary\r\n on how many FSS there will be.\r\n
\r\n This qualification needs to be renewed every 5 years.
\r\n \r\n Under Standard 3.2.2A -{\" \"}\r\n category one and two businesses must: \r\n
\r\n \r\n \r\n appoint a certified Food Safety Supervisor (FSS) before\r\n engaging in a ‘prescribed activity’\r\n \r\n \r\n the certificate must be from either a registered training\r\n organisation or an organisation recognised by the relevant\r\n food regulator, THAT’S US!\r\n \r\n \r\n the certificate must have been obtained within the past 5\r\n years\r\n \r\n \r\n ensure that the FSS is reasonably available to advise and\r\n supervise each food handler engaged in that prescribed\r\n activity.\r\n \r\n \r\n \r\n Prescribed activities involve handling unpackaged potentially\r\n hazardous foods that are ready to eat, which are high risk.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Who should be a FSS?\",\r\n content: (\r\n <>\r\n \r\n \r\n The FSS should be in a position to oversee food handling and\r\n be involved in the day-to-day food handling operations of\r\n the food business.\r\n \r\n \r\n They must be ‘reasonably available’ as a point of contact\r\n for food handlers and authorised officers.\r\n \r\n \r\n ‘Reasonably available’ means the FSS works onsite and\r\n oversees food handling of high-risk unpackaged foods, or can\r\n be easily contacted (e.g. by phone).\r\n \r\n \r\n It is not considered reasonable for a business to appoint\r\n someone as a FSS who does not regularly handle food as part\r\n of their normal duties, or is never onsite at a food\r\n business.\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Role of the FSS\",\r\n content: (\r\n <>\r\n \r\n The FSS makes sure the business is handling food safely, so if\r\n something goes wrong, food that could be unsafe to eat is not\r\n processed further or served to consumers.\r\n
\r\n The role of the FSS is to:
\r\n \r\n \r\n make sure Food Safety risks are managed and issues are\r\n prevented or corrected\r\n \r\n \r\n instruct staff, review and update business procedures, and\r\n inspect premises and food handling operations\r\n \r\n \r\n share their Food Safety knowledge with other food handlers\r\n \r\n \r\n foster a positive Food Safety culture, so Food Safety is a\r\n top priority in ‘the way we do things here’\r\n \r\n \r\n \r\n The business needs to make sure the FSS is able to fulfil\r\n these duties.\r\n
\r\n \r\n \r\n
\r\n \r\n This Food Safety Supervisor training applies to: hospitality,\r\n retail and tourism enterprises. It is particularly relevant to\r\n staff working in these industries, such as kitchen hands,\r\n cooks, chefs, catering staff, bar staff, food and beverage\r\n attendants, housekeeping and laundry staff, sandwich hands,\r\n cafe and fast-food outlet’s, cooking crew, salespeople,\r\n owner-operators of small business catering operations or any\r\n retail food outlets involving the preparation of food.\r\n
\r\n \r\n This Food Safety training will also apply to any venue that\r\n operates a permanent or temporary kitchen or smaller food\r\n preparation area, such as restaurants, cafes, clubs, hotels,\r\n attractions, events and conference venues, fast- food\r\n restaurants, retail food outlets such as sandwich shops and\r\n food court outlets. It would also apply to tour operators\r\n involved in the preparation and service of food at temporary\r\n sites.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n Our course is designed to be as flexible and straightforward\r\n as possible! We pride ourselves on our learning platform which\r\n is filled with many short DVD's and visual images making this\r\n training course a fast and effective way to obtain your\r\n Nationally Accredited Certificate.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lock outs\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Safety training, we also offer you\r\n a downloadable course workbook. This online course material is\r\n always updated so we encourage you to log back in any time\r\n after your training and obtain any new Food Safety\r\n information, this is especially helpful when training up new\r\n staff and when council come around!\r\n
\r\n \r\n This Food Safety Supervisor course prepares you with an\r\n extensive understanding of the role a Food Safety Supervisor\r\n must play within the workplace.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Safety Legislation\",\r\n content: (\r\n <>\r\n \r\n \r\n Please click for more information on the link below for your\r\n States or Territories Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default FoodSafetySupervisorCertificateHospitalityAndRetail;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst FoodHandlingLevel1CertificateHospitalityAndRetail = () => {\r\n return (\r\n <>\r\n \r\n \r\n All Food Handlers in Australia must be trained in Food Safety.\r\n Our Food Handling Certificate course is designed to meet these\r\n legal requirements and helps to protect customers from\r\n food-related illnesses and incidents.\r\n
\r\n \r\n The Food Handler is classified as any person who directly\r\n handles food or food contact surfaces such as cutlery, plates,\r\n and bowls. Food Handling activities include: preparing,\r\n serving, packing, displaying, and storing food.\r\n
\r\n \r\n People at many levels use this skill in the workplace during\r\n their daily activities, including cooks, chefs, caterers,\r\n kitchen stewards, kitchen hands, bar staff, food attendants,\r\n and room attendants in the hospitality and retail industries.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Is this course for me?\",\r\n content: (\r\n <>\r\n \r\n This course is designed for all people handling food in the\r\n Hospitality and Retail Service industries.\r\n
\r\n \r\n Under Standard 3.2.2A, all staff who handle unpackaged,\r\n potentially hazardous food must be trained in Food Safety and\r\n be able to show they have appropriate skills and knowledge.\r\n This is different from the Food Safety Supervisor requirement.\r\n
\r\n Food Handlers are required to:
\r\n \r\n \r\n Have Food Safety skills and knowledge as per Standard 3.2.2A\r\n \r\n Be able to demonstrate this to a Health Inspector \r\n Handle food in a safe and hygienic manner \r\n \r\n \r\n Businesses can choose how Food Handlers are trained, but the\r\n training must cover:\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n Rest assured, when you enrol with us, you have access to\r\n everything you need to be accredited as a qualified Food\r\n Handler in Australia.\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n This unit of competency describes the skills and knowledge\r\n required for basic Food Handling practices within the\r\n Hospitality and Retail sector.\r\n
\r\n \r\n The content of the course ensures that individuals are aware\r\n of their responsibilities as a Food Handler and provides\r\n comprehensive information about personal hygiene and best\r\n practices for ensuring Food Safety.\r\n
\r\n \r\n At the end of the course, students are expected to be able to\r\n identify Food Safety hazards in the workplace and know what to\r\n do if a Food Safety incident occurs.\r\n
\r\n \r\n Our Food Handler course is designed to be as flexible and\r\n straightforward as possible! We pride ourselves on our\r\n learning platform which is filled with many short DVD's and\r\n visual images, making this training course a fast and\r\n effective way to obtain your Nationally Accredited\r\n Certificate.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lockouts\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Handling training, we also offer\r\n you a downloadable course workbook. This online course\r\n material is always updated so we encourage you to log back in\r\n any time after your training and obtain any new Food Safety\r\n information. This is especially helpful when you need to\r\n refresh your Food Safety skills and when council comes around!\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Safety Legislation\",\r\n content: (\r\n <>\r\n \r\n \r\n Please click for more information on the link below for your\r\n States or Territories Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default FoodHandlingLevel1CertificateHospitalityAndRetail;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst FoodHandlingLevel2CertificateHospitalityAndRetail = () => {\r\n return (\r\n <>\r\n \r\n \r\n All Food Handlers in Australia must be trained in Food Safety.\r\n Our Food Handling Certificate course (Level 2) is designed to\r\n meet these legal requirements and helps to protect customers\r\n from food-related illnesses and incidents.\r\n
\r\n \r\n This course is designed for all people supervising food\r\n operations in the Hospitality or Retail food industries. This\r\n course is also known as Level 2 of the Food Safety Supervisor\r\n qualification.\r\n
\r\n \r\n People at many levels use this skill in the workplace during\r\n their daily activities, including cooks, chefs, caterers,\r\n kitchen stewards, kitchen hands, bar staff, food attendants,\r\n and room attendants in the hospitality and retail industries.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Is this course for me?\",\r\n content: (\r\n <>\r\n \r\n This course is perfect for people who have completed Level 1 -\r\n Food Handling in Hospitality & Retail and wish to further\r\n their Food Safety skills and responsibilities.\r\n
\r\n \r\n The two completed units (Level 1 & 2) make up the Food Safety\r\n Supervisor qualification.\r\n
\r\n \r\n Under the Standard 3.2.2A, all staff who handle unpackaged,\r\n potentially hazardous food must be trained in Food Safety and\r\n be able to show they have appropriate skills and knowledge.\r\n This is different from the Food Safety Supervisor requirement.\r\n
\r\n Food Handlers are required to:
\r\n \r\n \r\n Have Food Safety skills and knowledge as per Standard 3.2.2A\r\n \r\n Be able to demonstrate this to a Health Inspector \r\n Handle food in a safe and hygienic manner \r\n \r\n \r\n Businesses can choose how Food Handlers are trained, but the\r\n training must cover:\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n Rest assured, when you enrol with us, you have access to\r\n everything you need to be accredited as a qualified Food\r\n Handler in Australia.\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n This unit applies to all tourism, hospitality, retail, and\r\n catering organisations with permanent or temporary kitchen\r\n premises or smaller food preparation areas.\r\n
\r\n Critical aspects of this training include:
\r\n \r\n \r\n Consistently use safe Food Handling practices in a range of\r\n different Food Handling circumstances\r\n \r\n \r\n Demonstrate knowledge of a Food Safety program and\r\n requirements, including critical control points and methods\r\n of food hazard control for each critical control point\r\n \r\n \r\n Take corrective actions within the scope of job\r\n responsibility for incidents where food hazards are not\r\n controlled\r\n \r\n \r\n \r\n Our Food Handler (Level 2) course is designed to be as\r\n flexible and straightforward as possible! We pride ourselves\r\n on our learning platform which is filled with many short DVD's\r\n and visual images, making this training course a fast and\r\n effective way to obtain your Nationally Accredited\r\n Certificate.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lockouts\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Handling training, we also offer\r\n you a downloadable course workbook. This online course\r\n material is always updated so we encourage you to log back in\r\n any time after your training and obtain any new Food Safety\r\n information. This is especially helpful when you need to\r\n refresh your Food Safety skills and when council comes around!\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Safety Legislation\",\r\n content: (\r\n <>\r\n \r\n \r\n Please click for more information on the link below for your\r\n States or Territories Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default FoodHandlingLevel2CertificateHospitalityAndRetail;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst FoodHandlingLevel1CertificateHealthAndCommunity = () => {\r\n return (\r\n <>\r\n \r\n \r\n All Food Handlers in Australia must be trained in Food Safety.\r\n Our Food Handling Certificate course is designed to meet these\r\n legal requirements and helps to protect customers from\r\n food-related illnesses and incidents.\r\n
\r\n \r\n The Food Handler is classified as any person who directly\r\n handles food or food contact surfaces such as cutlery, plates,\r\n and bowls. Food Handling activities include: preparing,\r\n serving, packing, displaying, and storing food.\r\n
\r\n \r\n People at many levels use this skill in the workplace during\r\n their daily activities, including cooks, chefs, caterers,\r\n kitchen stewards, kitchen hands, bar staff, food attendants,\r\n and room attendants in the Health and Community industries.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Is this course for me?\",\r\n content: (\r\n <>\r\n \r\n This course is designed for all people handling food in the\r\n Community and Health Service industries.\r\n
\r\n \r\n Under the Standard 3.2.2A, all staff who handle unpackaged,\r\n potentially hazardous food must be trained in Food Safety and\r\n be able to show they have appropriate skills and knowledge.\r\n This is different from the Food Safety Supervisor requirement.\r\n
\r\n Food Handlers are required to:
\r\n \r\n \r\n Have Food Safety skills and knowledge as per Standard 3.2.2A\r\n \r\n Be able to demonstrate this to a Health Inspector \r\n Handle food in a safe and hygienic manner \r\n \r\n \r\n Businesses can choose how Food Handlers are trained, but the\r\n training must cover:\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n Rest assured, when you enrol with us, you have access to\r\n everything you need to be accredited as a qualified Food\r\n Handler in Australia.\r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n This unit of competency describes the skills and knowledge\r\n required for basic Food Handling practices. You will\r\n understand Food Safety principles and regulations and ensure\r\n the lowest possible risk to this vulnerable population.\r\n
\r\n \r\n The content of the course ensures that individuals are aware\r\n of their responsibilities as a Food Handler and provides\r\n comprehensive information about personal hygiene and best\r\n practices for ensuring Food Safety.\r\n
\r\n \r\n At the end of the course, students are expected to be able to\r\n identify Food Safety hazards in the workplace and know what to\r\n do if a Food Safety incident occurs.\r\n
\r\n \r\n Our Food Handler course is designed to be as flexible and\r\n straightforward as possible! We pride ourselves on our\r\n learning platform which is filled with many short DVD's and\r\n visual images, making this training course a fast and\r\n effective way to obtain your Nationally Accredited\r\n Certificate.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lockouts\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Handling training, we also offer\r\n you a downloadable course workbook. This online course\r\n material is always updated so we encourage you to log back in\r\n any time after your training and obtain any new Food Safety\r\n information. This is especially helpful when you need to\r\n refresh your Food Safety skills and when council comes around!\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Safety Legislation\",\r\n content: (\r\n <>\r\n \r\n \r\n Please click for more information on the link below for your\r\n States or Territories Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default FoodHandlingLevel1CertificateHealthAndCommunity;\r\n","import React from \"react\";\r\nimport ContentCollapsiblePanel from \"components/Common/content-collapsible-panel\";\r\n\r\nconst FoodSafetySupervisorCertificateHealthAndCommunity = () => {\r\n return (\r\n <>\r\n \r\n \r\n When you enrol with us, you have access to everything you need\r\n to be accredited as a qualified Food Safety Supervisor (FSS)\r\n in Australia.\r\n
\r\n \r\n \r\n *If you are in{\" \"}\r\n \r\n Childcare \r\n {\" \"}\r\n in NSW, please do the NSW specific training. Not this one!\r\n \r\n
\r\n \r\n \r\n As NSW Aged Care providers are licensed , the required\r\n training comes under their Food Safety Plan. If you reside\r\n in NSW and work with vulnerable persons, we strongly suggest\r\n talking to your Food Safety auditor or ring the NSW Food\r\n Authority before you begin your training. Ph:{\" \"}\r\n 1300 552 406 \r\n \r\n
\r\n \r\n Under FSANZ Standard 3.2.2A, all Australian businesses that\r\n serve food must have one or more qualified Food Safety\r\n Supervisors. A Food Safety Supervisor is someone who has the\r\n appropriate Food Safety training to supervise Food Safety in a\r\n business. Food Safety Supervisors are mainly responsible for:\r\n
\r\n \r\n Supervising Food Handling Staff \r\n Maintaining the Food Safety Program \r\n \r\n Ensuring Safe Food Handling Practices across the business\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Is this course for me?\",\r\n content: (\r\n <>\r\n \r\n Either way, it is a requirement that a Food Safety Supervisor\r\n is appointed to the food business. Depending on how large the\r\n food operation is, or how available the FSS can be, will vary\r\n on how many FSS there will be.\r\n
\r\n This qualification needs to be renewed every 5 years.
\r\n \r\n Under Standard 3.2.2A - category one and two businesses must:\r\n
\r\n \r\n \r\n Appoint a certified Food Safety Supervisor (FSS) before\r\n engaging in a ‘prescribed activity’\r\n \r\n \r\n The certificate must be from either a registered training\r\n organisation or an organisation recognised by the relevant\r\n food regulator, THAT’S US!\r\n \r\n \r\n The certificate must have been obtained within the past 5\r\n years\r\n \r\n \r\n Ensure that the FSS is reasonably available to advise and\r\n supervise each food handler engaged in that prescribed\r\n activity.\r\n \r\n \r\n \r\n Prescribed activities involve handling unpackaged, potentially\r\n hazardous foods that are ready to eat, which are high risk.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Who should be a FSS?\",\r\n content: (\r\n <>\r\n \r\n \r\n The FSS should be in a position to oversee food handling and\r\n be involved in the day-to-day food handling operations of\r\n the food business.\r\n \r\n \r\n They must be ‘reasonably available’ as a point\r\n of contact for food handlers and authorised officers.\r\n \r\n \r\n ‘Reasonably available’ means the FSS works\r\n onsite and oversees food handling of high-risk unpackaged\r\n foods, or can be easily contacted (e.g. by phone).\r\n \r\n \r\n It is not considered reasonable for a business to appoint\r\n someone as a FSS who does not regularly handle food as part\r\n of their normal duties or is never onsite at a food\r\n business.\r\n \r\n \r\n >\r\n ),\r\n },\r\n {\r\n title: \"Role of the FSS\",\r\n content: (\r\n <>\r\n \r\n The FSS makes sure the business is handling food safely, so if\r\n something goes wrong, food that could be unsafe to eat is not\r\n processed further or served to consumers.\r\n
\r\n The role of the FSS is to:
\r\n \r\n \r\n Ensure all your food handling staff complete the necessary\r\n Food Safety training\r\n \r\n \r\n Make sure Food Safety risks are managed and issues are\r\n prevented or corrected\r\n \r\n \r\n Instruct staff, review and update business procedures, and\r\n inspect premises and food handling operations\r\n \r\n \r\n Share their Food Safety knowledge with other food handlers\r\n \r\n \r\n Foster a positive Food Safety culture, so Food Safety is a\r\n top priority in ‘the way we do things here’\r\n \r\n \r\n \r\n The business needs to make sure the FSS is able to fulfil\r\n these duties.\r\n
\r\n \r\n \r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"Course Summary\",\r\n content: (\r\n <>\r\n \r\n These three units make up the Food Safety Supervisor\r\n Certificate for the Health and Communities sector. This course\r\n is designed for all people handling and supervising food in\r\n the Community and Health Service industries.\r\n
\r\n \r\n With this Food Safety training, you can better understand Food\r\n Safety principles and regulations and ensure the lowest\r\n possible risk to this vulnerable population.\r\n
\r\n \r\n Our course is designed to be as flexible and straightforward\r\n as possible! We pride ourselves on our learning platform which\r\n is filled with many short DVD's and visual images making this\r\n training course a fast and effective way to obtain your\r\n Nationally Accredited Certificate.\r\n
\r\n \r\n All our training courses allow students to complete their\r\n course in their own time. That's right, there are no lockouts\r\n and no penalties if you get any answers wrong!\r\n
\r\n \r\n On completion of your Food Safety training, we also offer you\r\n a downloadable course workbook. This online course material is\r\n always updated so we encourage you to log back in any time\r\n after your training and obtain any new Food Safety\r\n information. This is especially helpful when training up new\r\n staff and when council come around!\r\n
\r\n \r\n This Food Safety Supervisor course prepares you with an\r\n extensive understanding of the role a Food Safety Supervisor\r\n must play within the workplace.\r\n
\r\n >\r\n ),\r\n },\r\n {\r\n title: \"State Food Safety Legislation\",\r\n content: (\r\n <>\r\n \r\n \r\n Please click for more information on the link below for your\r\n States or Territories Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Queensland Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Victorian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n ACT Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n South Australian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n NSW Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Western Australia Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Tasmanian Food Safety Legislation\r\n \r\n
\r\n \r\n \r\n Northern Territory Food Safety Legislation\r\n \r\n
\r\n >\r\n ),\r\n },\r\n ]}\r\n />\r\n >\r\n );\r\n};\r\n\r\nexport default FoodSafetySupervisorCertificateHealthAndCommunity;\r\n","import React, { useState, useEffect } from \"react\";\r\nimport { useParams } from \"react-router-dom\";\r\nimport { Col, Row } from \"reactstrap\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport LinkButton from \"components/link-button/link-button\";\r\nimport Infographic from \"features/infographic/infographic\";\r\nimport { courses } from \"constants/course-content\";\r\nimport { getCourseContent } from \"./course-content\";\r\nimport \"./course-info-page.scss\";\r\n\r\nconst CourseInfoPage = () => {\r\n const { courseSlug } = useParams();\r\n\r\n const [course, setCourse] = useState(null);\r\n\r\n useEffect(() => {\r\n const course = courses.find(\r\n (course) =>\r\n course.courseReadMorePage === `/courses/${courseSlug.toLowerCase()}/`\r\n );\r\n setCourse(course);\r\n }, [courseSlug]);\r\n\r\n return (\r\n \r\n {course && (\r\n <>\r\n \r\n \r\n
\r\n
{course.courseInfo.heading} \r\n
\r\n \r\n {course.courseInfo.units.map((unit, index) => (\r\n \r\n {unit}\r\n \r\n ))}\r\n {course.courseInfo.intro} \r\n ${course.courseCost}
\r\n \r\n {course.courseInfo.additionalContent && (\r\n <>{course.courseInfo.additionalContent}>\r\n )}\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n {getCourseContent(course.courseId)}\r\n \r\n
\r\n
\r\n >\r\n )}\r\n \r\n );\r\n};\r\n\r\nexport default CourseInfoPage;\r\n","import React from \"react\";\r\nimport NswFoodSafetySupervisorCertificate from \"./nsw-food-safety-supervisor-certificate\";\r\nimport NswFoodSafetySupervisorCertificateRefresher from \"./nsw-food-safety-supervisor-certificate-refresher\";\r\nimport FoodSafetySupervisorCertificateHospitalityAndRetail from \"./food-safety-supervisor-certificate-hospitality-and-retail\";\r\nimport FoodHandlingLevel1CertificateHospitalityAndRetail from \"./food-handling-level-1-certificate-hospitality-and-retail\";\r\nimport FoodHandlingLevel2CertificateHospitalityAndRetail from \"./food-handling-level-2-certificate-hospitality-and-retail\";\r\nimport FoodHandlingLevel1CertificateHealthAndCommunity from \"./food-handling-level-1-certificate-health-and-community\";\r\nimport FoodSafetySupervisorCertificateHealthAndCommunity from \"./food-safety-supervisor-certificate-health-and-community\";\r\n\r\nexport const getCourseContent = (courseId) => {\r\n switch (courseId) {\r\n case 6:\r\n return ;\r\n case 8:\r\n return ;\r\n case 4:\r\n return ;\r\n case 2:\r\n return ;\r\n case 3:\r\n return ;\r\n case 1009:\r\n return ;\r\n case 1008:\r\n return ;\r\n default:\r\n return <>>;\r\n }\r\n};\r\n","import HttpClient from \"coreLib/http/httpClient\";\r\n\r\nconst ApiService = () => {\r\n let httpClient = HttpClient();\r\n\r\n const getSso = async (userCourseContentToken) => {\r\n return await httpClient.get(\r\n `/v1/usercourse/${userCourseContentToken}/elearnd-sso`\r\n );\r\n };\r\n\r\n return {\r\n getSso,\r\n };\r\n};\r\n\r\nexport default ApiService;\r\n","/**\r\n * Action Creator definitions\r\n */\r\nimport { ActionTypes } from \"./action-types\";\r\nimport { addNotification } from \"redux/system/system-action-creators\";\r\nimport UserCourseService from \"services/user-course-service\";\r\nimport CourseService from \"services/course-service\";\r\nimport ApiService from \"../services/api-service\";\r\n\r\n// ----------------------------\r\n// Actions\r\n// ----------------------------\r\n\r\nexport const onLoadSection = (courseContentToken, history) => {\r\n return async (dispatch) => {\r\n dispatch(loadSectionRequest());\r\n\r\n const userCourseService = UserCourseService();\r\n\r\n await userCourseService\r\n .getCourseDetailsAndStatus(courseContentToken)\r\n .then(async (resp) => {\r\n const { id, status } = resp.data;\r\n if (!status.isExternalLearning) {\r\n history.push(\"/Your-Courses/\");\r\n } else if (!status.courseExpired) {\r\n const courseService = CourseService();\r\n\r\n const course = courseService.getCourse(id);\r\n\r\n dispatch(loadSectionSuccess(course.courseTitle));\r\n } else {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n }\r\n })\r\n .catch((err) => {\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong loading your course information. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n history.push(\"/your-courses/\");\r\n });\r\n };\r\n};\r\n\r\nexport const onLoadSso = (courseContentToken) => {\r\n return async (dispatch) => {\r\n dispatch(loadSsoRequest());\r\n\r\n const apiService = ApiService();\r\n\r\n await apiService\r\n .getSso(courseContentToken)\r\n .then((resp) => {\r\n window.location.href = resp.data;\r\n })\r\n .catch(() => {\r\n dispatch(loadSsoFailure());\r\n\r\n dispatch(\r\n addNotification(\r\n \"Sorry, something went wrong trying to login to eLearnd. Please try again. If the problem continues, please contact us for assistance.\",\r\n \"error\"\r\n )\r\n );\r\n });\r\n };\r\n};\r\n\r\nconst loadSectionRequest = () => ({\r\n type: ActionTypes.EXTERNAL_LEARNING_COURSE_LOAD_REQUEST,\r\n});\r\n\r\nconst loadSectionSuccess = (courseName) => ({\r\n type: ActionTypes.EXTERNAL_LEARNING_COURSE_LOAD_SUCCESS,\r\n payload: {\r\n courseName,\r\n },\r\n});\r\n\r\nconst loadSsoRequest = () => ({\r\n type: ActionTypes.EXTERNAL_LEARNING_COURSE_GET_SSO_REQUEST,\r\n});\r\n\r\nconst loadSsoFailure = () => ({\r\n type: ActionTypes.EXTERNAL_LEARNING_COURSE_GET_SSO_FAILURE,\r\n});\r\n","import React, { useEffect } from \"react\";\r\nimport { useParams } from \"react-router-dom\";\r\nimport { connect } from \"react-redux\";\r\nimport ContentSection from \"components/Common/content-section\";\r\nimport PageTagging from \"components/Common/page-tagging/page-tagging\";\r\nimport { selectExternalLearningCourse } from \"./redux/reducer\";\r\nimport * as actionCreators from \"./redux/action-creators\";\r\nimport ButtonFx from \"components/Common/Button-Fx/Button-Fx\";\r\n\r\nconst ExternalLearningCourseView = ({\r\n externalLearningCourse,\r\n onLoadSection,\r\n onLoadSso,\r\n}) => {\r\n const { courseName, isLoading, isLoadingSso } = externalLearningCourse;\r\n\r\n const { id } = useParams();\r\n\r\n useEffect(() => {\r\n onLoadSection(id);\r\n }, [id]);\r\n\r\n return (\r\n \r\n \r\n \r\n {!isLoading && (\r\n <>\r\n
{courseName} \r\n \r\n Your course is ready for you on eLearnd, our learning platform.\r\n \r\n Simply click the button below to get access your course. \r\n onLoadSso(id)}\r\n >\r\n Continue Course\r\n \r\n >\r\n )}\r\n \r\n \r\n );\r\n};\r\n\r\nfunction mapStateToProps(state) {\r\n const externalLearningCourse = selectExternalLearningCourse(state);\r\n\r\n return {\r\n externalLearningCourse: externalLearningCourse,\r\n };\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch, ownProps) => ({\r\n dispatch: dispatch,\r\n history: ownProps.history,\r\n});\r\n\r\nconst mergeFormProps = (stateProps, dispatchProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n onLoadSection: (courseContentToken) => {\r\n dispatchProps.dispatch(\r\n actionCreators.onLoadSection(courseContentToken, dispatchProps.history)\r\n );\r\n },\r\n onLoadSso: (courseContentToken) => {\r\n dispatchProps.dispatch(actionCreators.onLoadSso(courseContentToken));\r\n },\r\n});\r\n\r\nconst ExternalLearningCourse = connect(\r\n mapStateToProps,\r\n mapDispatchToProps,\r\n mergeFormProps\r\n)(ExternalLearningCourseView);\r\n\r\nexport default ExternalLearningCourse;\r\n","import React from \"react\";\r\nimport { BrowserRouter as Router, Switch, Route } from \"react-router-dom\";\r\nimport { Provider } from \"react-redux\";\r\nimport PrivateRoute from \"./components/Common/Private-Route/Private-Route\";\r\nimport ConfigureStore from \"./redux/configure-store\";\r\nimport ScrollToTop from \"./components/Scroll-To-Top/Scroll-To-Top\";\r\nimport ToastNotificationContainer from \"./components/Common/Toast/Toast-Container\";\r\nimport ErrorModalContainer from \"./components/Common/Error-Modal/Error-Modal-Container\";\r\nimport Header from \"./components/Header/header\";\r\nimport FooterContainer from \"./components/Footer/Footer.Container\";\r\nimport Home from \"./views/Home/home\";\r\nimport ContactUs from \"./views/Contact-Us/contact-us\";\r\nimport Login from \"./views/Login/login\";\r\nimport NewEnrolment from \"./views/Course-Enrolment/New-Enrolment/new-enrolment\";\r\nimport Step1FormContainer from \"./views/Course-Enrolment/Step-1/Step-1-Form.Container\";\r\nimport Step2FormContainer from \"./views/Course-Enrolment/Step-2/Step-2-Form.Container\";\r\nimport Step3FormContainer from \"./views/Course-Enrolment/Step-3/Step-3-Form.Container\";\r\nimport CorporateVouchers from \"./views/Coporate-Vouchers/corporate-vouchers.container\";\r\nimport CorporatePurchaseVouchers from \"./views/Purchase-Corporate-Vouchers/purchase-corporate-vouchers.container\";\r\nimport CourseContentContainer from \"./views/Course-Content/Course-Content.Container\";\r\nimport CourseQuizContainer from \"./views/Course-Quiz/Course-Quiz.Container\";\r\nimport ContentPage from \"./views/Content-Page\";\r\nimport Certificates from \"./views/Certificates/certificates\";\r\nimport CertificateRegister from \"views/Certificates/certificate-register\";\r\nimport Start from \"./views/Start/start\";\r\nimport CorporateVouchersRegister from \"./views/Corporate-Vouchers/corporate-vouchers-register\";\r\nimport ThirdPartyFormContainer from \"./views/Third-Party-Form/Third-Party-Form.Container\";\r\nimport UpdateProfile from \"./views/Update-Profile/Update-Profile.Container\";\r\nimport ChangePassword from \"./views/Change-Password/Change-Password.Container\";\r\nimport Error403 from \"./views/Pages/403/Error-403\";\r\nimport ForgotPasswordView from \"./views/Forgot-Password/Forgot-Password-View\";\r\nimport ResetPasswordView from \"./views/Forgot-Password/Reset-Password-View\";\r\nimport NSWReprint from \"./views/NSW-Reprint-Page/nsw-reprint-page.container\";\r\nimport CorporateTaxInvoice from \"./views/Corporate-Tax-Invoice/corporate-tax-invoice.container\";\r\n\r\nimport \"./App.scss\";\r\nimport FAQs from \"./views/FAQs/faqs\";\r\nimport CourseCompletedContainer from \"./views/Course-Completed/Course-Completed.Container\";\r\nimport CourseSurveyContainer from \"./views/Course-Survey/Course-Survey.Container\";\r\nimport PrintCourseContentGuide from \"./views/Print-Course-Content-Guide/Print-Course-Content-Guide\";\r\n//Admin Pages\r\nimport Users from \"./views/Admin/Users/users.container\";\r\nimport UserCourses from \"./views/Admin/UserCourses/users-courses.container\";\r\nimport EditUserCourse from \"./views/Admin/Edit-User-Course/edit-user-course.container\";\r\nimport DowloadReportsPage from \"./views/Admin/Download-Reports/download-reports.container\";\r\nimport VoucherPurchases from \"./views/Admin/View-Voucher-Purchases/voucher-purchases.container\";\r\nimport NswCertificatesContainer from \"./views/Admin/Nsw-Certificates/Nsw-Certificates.Container\";\r\nimport NswReprintsViewContainer from \"./views/Admin/Nsw-Reprints-View/Nsw-Reprints-View.Container\";\r\nimport PromoCodesContainer from \"./views/Admin/Promo-Codes/promo-codes.container\";\r\nimport AppWrapperContainer from \"./components/Common/App-Wrapper/App-Wrapper-Container\";\r\nimport LoginImpersonationContainer from \"./components/Common/Login-Impersonation/Login-Impersonation.Container\";\r\nimport AuthoriseAvsContainer from \"./views/Avetmiss/Authorise-Avs/authorise-avs.container\";\r\nimport AvetmissReportingContainer from \"./views/Avetmiss/Avetmiss-Reporting/avetmiss-reporting.container\";\r\nimport AvetmissReportingSubmissionContainer from \"./views/Avetmiss/Avetmiss-Reporting-Submission/avetmiss-reporting-submission.container\";\r\nimport AvetmissReportingValidationContainer from \"./views/Avetmiss/Avetmiss-Reporting-Validation/avetmiss-reporting-validation.container\";\r\nimport AvetmissAddressValidation from \"./views/Avetmiss/Avetmiss-Address-Validation\";\r\nimport SyncView from \"./views/Admin/Sync/sync-view\";\r\nimport CourseInfoPage from \"views/Course-Info-Page/course-info-page\";\r\nimport eLearningCourse from \"views/external-learning-course/external-learning-course\";\r\n\r\nfunction App() {\r\n const store = ConfigureStore();\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {/* */}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {/* Admin Routes */}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {/* Admin Routes */}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n\r\nexport default App;\r\n","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import \"react-app-polyfill/ie9\";\r\nimport \"react-app-polyfill/stable\";\r\nimport React from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport \"bootstrap/dist/css/bootstrap.min.css\";\r\nimport \"./index.scss\";\r\nimport App from \"./App\";\r\nimport * as serviceWorker from \"./serviceWorker\";\r\n\r\nReactDOM.render( , document.getElementById(\"root\"));\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n","Object.defineProperty(exports, \"__esModule\", { value: true });\r\n\r\nrequire(\"react\");\r\nvar visa = require(\"./visa.js\");\r\nvar unionpay = require(\"./unionpay.js\");\r\nvar placeholder = require(\"./placeholder.js\");\r\nvar mastercard = require(\"./mastercard.js\");\r\nvar jcb = require(\"./jcb.js\");\r\nvar amex = require(\"./amex.js\");\r\nvar dinersclub = require(\"./dinersclub.js\");\r\nvar discover = require(\"./discover.js\");\r\nvar hipercard = require(\"./hipercard.js\");\r\n\r\nvar index = {\r\n amex: amex.default,\r\n dinersclub: dinersclub.default,\r\n discover: discover.default,\r\n hipercard: hipercard.default,\r\n jcb: jcb.default,\r\n unionpay: unionpay.default,\r\n mastercard: mastercard.default,\r\n placeholder: placeholder.default,\r\n visa: visa.default\r\n};\r\n\r\nexports.default = index;\r\n","module.exports = __webpack_public_path__ + \"static/media/infographic-1.5b14e8e6.svg\";","module.exports = __webpack_public_path__ + \"static/media/infographic-2.4e1138dd.svg\";","module.exports = __webpack_public_path__ + \"static/media/infographic-3.ca68e8f0.svg\";","module.exports = __webpack_public_path__ + \"static/media/infographic-4.b32e9f76.svg\";","module.exports = __webpack_public_path__ + \"static/media/infographic-5.2ba2f3f7.svg\";","module.exports = __webpack_public_path__ + \"static/media/green-tick.68ae9e29.svg\";","module.exports = __webpack_public_path__ + \"static/media/hltfse001.9c4b0a17.svg\";","module.exports = __webpack_public_path__ + \"static/media/hltfse005.86b01dfb.svg\";","module.exports = __webpack_public_path__ + \"static/media/hltfse007.79fcbb33.svg\";","module.exports = __webpack_public_path__ + \"static/media/sitxfsa005.4bfa9d1c.svg\";","module.exports = __webpack_public_path__ + \"static/media/sitxfsa006.3e05c55c.svg\";","module.exports = __webpack_public_path__ + \"static/media/fruit-bg.9f615b19.jpg\";","module.exports = __webpack_public_path__ + \"static/media/food-bg.0852897d.jpg\";"],"sourceRoot":""}