g(x,c))a[d]=x,a[n]=c,d=n;else break a}}return b}\nfunction g(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}if(\"object\"===typeof performance&&\"function\"===typeof performance.now){var l=performance;exports.unstable_now=function(){return l.now()}}else{var p=Date,q=p.now();exports.unstable_now=function(){return p.now()-q}}var r=[],t=[],u=1,v=null,y=3,z=!1,A=!1,B=!1,D=\"function\"===typeof setTimeout?setTimeout:null,E=\"function\"===typeof clearTimeout?clearTimeout:null,F=\"undefined\"!==typeof setImmediate?setImmediate:null;\n\"undefined\"!==typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function G(a){for(var b=h(t);null!==b;){if(null===b.callback)k(t);else if(b.startTime<=a)k(t),b.sortIndex=b.expirationTime,f(r,b);else break;b=h(t)}}function H(a){B=!1;G(a);if(!A)if(null!==h(r))A=!0,I(J);else{var b=h(t);null!==b&&K(H,b.startTime-a)}}\nfunction J(a,b){A=!1;B&&(B=!1,E(L),L=-1);z=!0;var c=y;try{G(b);for(v=h(r);null!==v&&(!(v.expirationTime>b)||a&&!M());){var d=v.callback;if(\"function\"===typeof d){v.callback=null;y=v.priorityLevel;var e=d(v.expirationTime<=b);b=exports.unstable_now();\"function\"===typeof e?v.callback=e:v===h(r)&&k(r);G(b)}else k(r);v=h(r)}if(null!==v)var w=!0;else{var m=h(t);null!==m&&K(H,m.startTime-b);w=!1}return w}finally{v=null,y=c,z=!1}}var N=!1,O=null,L=-1,P=5,Q=-1;\nfunction M(){return exports.unstable_now()-Qa||125d?(a.sortIndex=c,f(t,a),null===h(r)&&a===h(t)&&(B?(E(L),L=-1):B=!0,K(H,c-d))):(a.sortIndex=e,f(r,a),A||z||(A=!0,I(J)));return a};\nexports.unstable_shouldYield=M;exports.unstable_wrapCallback=function(a){var b=y;return function(){var c=y;y=b;try{return a.apply(this,arguments)}finally{y=c}}};\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/scheduler.production.min.js');\n} else {\n module.exports = require('./cjs/scheduler.development.js');\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","import React from 'react';\n\n\nclass Slide1 extends React.Component {\n constructor(props) {\n super(props);\n this.ctaButtonHandler = this.ctaButtonHandler.bind(this);\n this.state = {\n };\n }\n\n componentDidMount(){\n // init popovers\n $('[data-toggle=\"popover\"]').popover();\n \n // libraries/plugins not included correctly, so mitigating against bootstrap not being fully loaded yet when popover first initialised\n setTimeout (() => {\n $('[data-toggle=\"popover\"]').popover(); \n }, 1000);\n \n $(document).on(\"click\", \".popover .slide3__popover-cancel\", function () {\n $(this).parents(\".popover\").popover('hide');\n });\n }\n\n ctaButtonHandler() {\n const nextSlideIsOpen = document.querySelector('.slide-2') || document.querySelector('.slide-3') != null;\n\n if (nextSlideIsOpen) {\n this.props.journey === 1 ? this.props.custScrollTo(document.querySelector('.slide-2')) : this.props.custScrollTo(document.querySelector('.slide-3'))\n\n } else {\n this.props.openNextSlide()\n }\n }\n\n\n render() {\n return (\n \n {/* Desktop View */}\n
\n
\n
\n
\n
\n
{this.props.journey === 1 ? this.props.data?.bannerText : this.props.data?.savingsComponent.bannerText} \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
this.ctaButtonHandler()}>{this.props.journey === 1 ? this.props.data?.ctaButtonText : this.props.data?.savingsComponent.ctaButtonText} \n
\n \n {this.props.data?.copyrightLink} \n
\n
\n
\n
\n\n {/* Mobile view */}\n
\n
{this.props.journey === 1 ? this.props.data?.bannerText : this.props.data?.savingsComponent.bannerText} \n
\n
\n
\n
\n
\n
\n this.ctaButtonHandler()}>{this.props.journey === 1 ? this.props.data?.ctaButtonText : this.props.data?.savingsComponent.ctaButtonText} \n
\n
\n \n {this.props.data?.copyrightLink}
\n
\n {/* Info popup modal */}\n
\n
\n
\n
\n
Important information and assumptions \n \n \n
\n
\n
\n
\n
\n )\n }\n}\n\nexport default Slide1;\n","import React from 'react';\n\nclass Slide2 extends React.Component {\n constructor(props) {\n super(props);\n this.slide2 = React.createRef();\n this.handleScroll = this.handleScroll.bind(this);\n this.ctaButtonHandler = this.ctaButtonHandler.bind(this);\n this.state = {\n open: false,\n visible: false,\n };\n }\n\n\n componentDidMount() {\n this.props.custScrollTo(this.slide2.current)\n\n let $slide2Carousel = $('.slide2__carousel');\n $slide2Carousel.filter('.slick-initialized').slick('unslick');\n $slide2Carousel.slick({\n centerMode: true,\n initialSlide: 1,\n slidesToShow: 1,\n infinite: true,\n arrows: true,\n dots: true,\n variableWidth: true,\n nextArrow: \"Next \",\n prevArrow: \"Previous \",\n });\n \n window.addEventListener('scroll', this.handleScroll);\n }\n\n\n componentWillUnmount() {\n window.removeEventListener('scroll', this.handleScroll);\n }\n\n handleScroll() {\n let view = this.slide2.current.getBoundingClientRect();\n const Buffer = 5\n if (view.top <= Buffer) this.setState({ visible: true });\n if (this.state.visible && (view.top >= window.innerHeight / 2)) {\n this.props.closeSlide();\n }\n }\n\n getScreenWidth() {\n return window.innerWidth;\n }\n\n ctaButtonHandler() {\n const nextSlideIsOpen = document.querySelector('.slide-3') != null\n if (nextSlideIsOpen) {\n this.props.custScrollTo(document.querySelector('.slide-3'))\n } else {\n this.props.openNextSlide()\n }\n }\n\n render() {\n return (\n \n
\n
\n
{ this.props.data?.slide2.title } \n
\n
\n
\n\n
\n {this.props.data?.slide2Cards?.map((card, index) => (\n
\n
\n {card.isDefault &&
\n
Default option – No action or paperwork {this.getScreenWidth() > 1279 ? \"required\" : \"\"}
\n
\n }\n
\n
{card.headingText} \n
\n
\n
\n ))}\n
\n\n {/* Mobile mode */}\n
\n {this.props.data?.slide2Cards?.map((card, index) => (\n
\n
\n {card.isDefault &&
\n
Default option – No action or paperwork {this.getScreenWidth() > 1279 ? \"required\" : \"\"}
\n
\n }\n
\n
{card.headingText} \n
\n
\n
\n ))}\n
\n
\n
\n
\n
\n this.ctaButtonHandler()}>{this.props?.data?.slide2Cta} \n
\n
\n
\n
\n )\n }\n}\n\nexport default Slide2;\n","import React from 'react';\n\nclass Slide3 extends React.Component {\n constructor(props) {\n super(props);\n this.slide3 = React.createRef();\n this.handleScroll = this.handleScroll.bind(this);\n this.disableIosTextFieldZoom = this.disableIosTextFieldZoom.bind(this);\n this.minSavingsValue = 2000;\n this.savingsInputTimer = null;\n this.state = {\n collapseOpen: false,\n visible: false,\n currentAge: '',\n retireAge: 65,\n leavingReason: 1,\n gender: '',\n withdrawalYear: '',\n rawCurrentInvestment: 0,\n rawVestedInvestment: 0,\n rawVestedHarmonisedInvestment: 0,\n rawSavingsInvestment: 0,\n currentInvestment: '',\n vestedInvestment: '',\n vestedHarmonisedInvestment: '',\n savingsInvestment: '',\n rawSalaryValue: 0,\n salaryValue: '',\n withDrawalYearNextError: false,\n withDrawalYearMinError: false,\n withDrawalYearMinNote: false, \n withDrawlYearEagerValidation: false,\n formValid: false,\n bsTemplate: '
',\n dropContent: [\n { value: 0, text: \"Select a reason below\" },\n { value: 1, text: \"Resignation\" },\n { value: 2, text: \"Dismissal\" },\n { value: 3, text: \"Retrenchment\" }\n ]\n };\n }\n componentDidMount() {\n this.props.custScrollTo(this.slide3.current)\n $('[data-toggle=\"popover\"]').popover()\n $(\".fade\").addClass(\"in\")\n var customSelect = $('.c-custom-select');\n $(document).on(\"click\", \".popover .slide3__popover-cancel\", function () {\n $(this).parents(\".popover\").popover('hide');\n });\n\n // Options for custom Select\n jcf.setOptions('Select', {\n wrapNative: false,\n wrapNativeOnMobile: false,\n fakeDropInBody: false,\n maxVisibleItems: 4\n });\n\n jcf.replace(customSelect);\n\n window.addEventListener('scroll', this.handleScroll);\n\n this.disableIosTextFieldZoom();\n }\n\n\n componentWillUnmount() {\n window.removeEventListener('scroll', this.handleScroll);\n }\n\n handleScroll() {\n let view = this.slide3.current.getBoundingClientRect();\n const Buffer = 5\n if (view.top <= Buffer) this.setState({ visible: true });\n if (this.state.visible && (view.top >= window.innerHeight / 2)) {\n this.props.closeSlide();\n }\n }\n\n toggleCollapse() {\n this.setState({ collapseOpen: !this.state.collapseOpen })\n }\n\n\n disableIosTextFieldZoom() {\n\n const checkIsIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n\n if (!checkIsIOS) return;\n\n const el = document.querySelector('meta[name=viewport]');\n\n if (el !== null) {\n let content = el.getAttribute('content');\n let re = /maximum\\-scale=[0-9\\.]+/g;\n\n if (re.test(content)) {\n content = content.replace(re, 'maximum-scale=1.0');\n } else {\n content = [content, 'maximum-scale=1.0'].join(', ')\n }\n\n el.setAttribute('content', content);\n }\n }\n\n handleInvestmentValue(e, rawInvestmentVar, investmentVar) { \n \n // on savings component input\n // wait for timeout before enabling eager validation messages \n if (rawInvestmentVar === 'rawSavingsInvestment' && !this.state.withDrawlYearEagerValidation) {\n clearTimeout(this.savingsInputTimer);\n this.savingsInputTimer = setTimeout(()=>{\n this.setState({ withDrawalYearEagerValidation: true }, () => {\n this.handleWithdrawalYear(this.state.withdrawalYear);\n });\n }, 1500);\n }\n\n // pre-decimal formatting method\n let val = e.target.value;\n\n const startCursorPos = e.target.selectionStart\n const startLength = val.length;\n\n // strip non-numeric chars except '.'\n val = val.replace(/[^0-9\\.]+/g, '');\n\n\n // if nothing entered, return investment value to 0\n if (val == '') {\n this.setState({ [rawInvestmentVar]: 0, [investmentVar]: '' }, () => {\n this.validationCheck();\n\n if (rawInvestmentVar === 'rawSavingsInvestment') {\n this.handleWithdrawalYear(this.state.withdrawalYear);\n }\n })\n return;\n } \n\n // round decimals to 2 places (if exist)\n if (val.split('.')[1] && val.split('.')[1].length > 2) {\n val = parseFloat(val).toFixed(2);\n }\n\n // format thousands and add currency symbol\n const formattedVal = 'R' + val.replace(/\\B(?=(\\d{3})+(?!\\d))/g, \" \");\n\n const endLength = formattedVal.length;\n const newCursorPos = endLength - startLength + startCursorPos;\n\n if (val.match(/\\d+(?!\\w)/) !== null) {\n this.setState({ [rawInvestmentVar]: parseFloat(val), [investmentVar]: formattedVal }, () => {\n e.target.selectionStart = newCursorPos;\n e.target.selectionEnd = newCursorPos;\n this.validationCheck();\n\n if (rawInvestmentVar === 'rawSavingsInvestment') {\n this.handleWithdrawalYear(this.state.withdrawalYear);\n }\n });\n }\n }\n\n\n\n\n\n handleSalaryValue(e) {\n\n // pre-decimal formatting method\n let val = e.target.value;\n\n const startCursorPos = e.target.selectionStart\n const startLength = val.length;\n\n // strip non-numeric chars except '.'\n val = val.replace(/[^0-9\\.]+/g, '');\n\n // if nothing entered, return investment value to 0\n if (val == '') {\n this.setState({ rawSalaryValue: 0, salaryValue: '' }, () => {\n this.validationCheck();\n })\n return;\n }\n\n // round decimals to 2 places (if exist)\n if (val.split('.')[1] && val.split('.')[1].length > 2) {\n val = parseFloat(val).toFixed(2);\n }\n\n // format thousands and add currency symbol\n const formattedVal = 'R' + val.replace(/\\B(?=(\\d{3})+(?!\\d))/g, \" \");\n\n const endLength = formattedVal.length;\n const newCursorPos = endLength - startLength + startCursorPos;\n\n if (val.match(/\\d+(?!\\w)/) !== null) {\n this.setState({ rawSalaryValue: parseFloat(val), salaryValue: formattedVal }, () => {\n e.target.selectionStart = newCursorPos;\n e.target.selectionEnd = newCursorPos;\n this.validationCheck();\n });\n }\n\n }\n\n handleCurrentAge(e) {\n this.setState({ currentAge: e.target.value }, () => this.validationCheck());\n\n if (e.target.value < 18 || e.target.value > this.state.retireAge) {\n e.target.classList.add('has-error');\n } else {\n e.target.classList.remove('has-error');\n }\n }\n\n handleCurrentAgePopUp(e) {\n var popover = bootstrap.Popover.getInstance(document.getElementById('currentAgeInput'))\n if (e.target.value >= 18 && e.target.value <= this.state.retireAge) {\n popover.hide();\n } else {\n\n if (e.target.value < 18) {\n e.target.setAttribute('data-bs-content', e.target.getAttribute('data-bs-content-min'));\n } else if (e.target.value > this.state.retireAge) {\n e.target.setAttribute('data-bs-content', e.target.getAttribute('data-bs-content-max'));\n }\n\n popover.show();\n\n // popovers should be on tags (with a tabindex), this is a work-around to enable them to be dismissable when triggered by other elements\n $('[data-toggle=\"popover\"]').on('shown.bs.popover', function () {\n document.body.addEventListener('click', () => {\n popover.hide();\n }, { once: true })\n })\n }\n }\n\n handleLeaveReason(e) {\n this.setState({ leavingReason: e.target.value })\n }\n\n handleGender(index) {\n this.setState({ gender: index }, () => this.validationCheck())\n }\n\n // called on radio select and savings component input\n handleWithdrawalYear(index) {\n this.setState({ withdrawalYear: index }, () => this.validationCheck()); \n\n // only applies to savings component journey\n if (this.props.journey === 2) { \n \n // clear all errors\n this.setState({ withDrawalYearNextError: false }); \n this.setState({ withDrawalYearMinError: false }); \n this.setState({ withDrawalYearMinNote: false });\n\n // if have withdrawn this year\n if (index === 1) {\n\n // if savings less than min allowed, show note\n if(this.state.rawSavingsInvestment < this.minSavingsValue && (this.state.rawSavingsInvestment !== 0 || this.state.savingsInvestment !== '')){\n // eager show error \n if (this.state.withDrawalYearEagerValidation) {\n this.setState({ withDrawalYearMinNote: true }); \n } \n }\n\n\n // if savings more than min, show error\n if(this.state.rawSavingsInvestment >= this.minSavingsValue){\n this.setState({ withDrawalYearNextError: true }); \n }\n \n \n } \n\n // if haven't withdrawn this year\n if (index === 0) {\n\n // if savings less than min allowed, show error\n if(this.state.rawSavingsInvestment < this.minSavingsValue && (this.state.rawSavingsInvestment !== 0 || this.state.savingsInvestment !== '')){\n\n // eager show error \n if (this.state.withDrawalYearEagerValidation) {\n this.setState({ withDrawalYearMinError: true }); \n } \n } \n\n \n }\n\n }\n }\n\n handleWithdrawalYearBlur(index) {\n \n if (this.state.withDrawlYearEagerValidation) { \n this.handleWithdrawalYear(index); \n } else {\n this.setState({ withDrawalYearEagerValidation: true }, () => {\n this.handleWithdrawalYear(index);\n });\n }\n \n }\n \n\n handleRetireAge(e) {\n this.setState({ retireAge: e.target.value }, () => this.validationCheck());\n\n if (e.target.value < 55 || e.target.value > 89) {\n e.target.classList.add('has-error');\n } else {\n e.target.classList.remove('has-error');\n }\n }\n\n handleRetireAgePopUp(e) {\n var popover = bootstrap.Popover.getInstance(document.getElementById('retAgeInput'))\n if (e.target.value >= 55 && e.target.value <= 89) {\n popover.hide();\n }\n else {\n\n if (e.target.value < 55) {\n e.target.setAttribute('data-bs-content', e.target.getAttribute('data-bs-content-min'));\n } else if (e.target.value > 89) {\n e.target.setAttribute('data-bs-content', e.target.getAttribute('data-bs-content-max'));\n }\n\n popover.show();\n\n // popovers should be on tags (with a tabindex), this is a work-around to enable them to be dismissable when triggered by other elements\n $('[data-toggle=\"popover\"]').on('shown.bs.popover', function () {\n document.body.addEventListener('click', () => {\n popover.hide();\n }, { once: true })\n })\n }\n }\n\n handleSalaryValuePopUp(e) {\n var popover = bootstrap.Popover.getInstance(document.getElementById('salaryAmount'));\n\n if (e.target.value !== '') {\n popover.hide();\n }\n else { \n popover.show();\n\n // popovers should be on tags (with a tabindex), this is a work-around to enable them to be dismissable when triggered by other elements\n $('[data-toggle=\"popover\"]').on('shown.bs.popover', function () {\n document.body.addEventListener('click', () => {\n popover.hide();\n }, { once: true })\n })\n }\n }\n \n\n\n validationCheck() {\n let isFormValid = true;\n \n if (this.state.currentAge < 18 || this.state.currentAge > this.state.retireAge) {\n isFormValid = false;\n }\n if (this.state.retireAge < 55 || this.state.retireAge > 89) {\n isFormValid = false;\n }\n if (this.state.rawSalaryValue === 0 && this.state.salaryValue === '') {\n isFormValid = false;\n }\n if (this.state.gender === '') {\n isFormValid = false;\n }\n if (this.state.withdrawalYear === ''){\n isFormValid = false;\n }\n\n // on exit journey: invalid if...\n if(this.props.journey === 1){\n\n // both vested amounts are 0 AND either retirement is 0 or savings is blank\n if (this.state.rawVestedInvestment === 0 && this.state.rawVestedHarmonisedInvestment === 0 && (this.state.savingsInvestment === '' || this.state.rawCurrentInvestment === 0) ) {\n isFormValid = false;\n } \n\n\n }\n \n // on savings journey: invalid if...\n if(this.props.journey === 2){\n\n // savings component amount is 0\n if (this.state.rawSavingsInvestment === 0 ) {\n isFormValid = false;\n }\n\n // have withdrawn this tax year & savings amount is 2000 or greater\n // OR have not withdrawn, but savings amount is less than 2000\n if ((this.state.withdrawalYear === 1 && this.state.rawSavingsInvestment >= this.minSavingsValue) ||\n (this.state.withdrawalYear === 0 && this.state.rawSavingsInvestment < this.minSavingsValue)) {\n isFormValid = false;\n }\n }\n \n \n this.setState({ formValid: isFormValid });\n return isFormValid;\n }\n\n handleForm(e) {\n e.preventDefault();\n\n if (this.validationCheck()) {\n\n this.props.setFormValues({\n currentAge: this.state.currentAge,\n retireAge: this.state.retireAge,\n gender: this.state.gender,\n leavingReason: this.state.leavingReason,\n currentInvestment: this.state.rawCurrentInvestment,\n vestedInvestment: this.state.rawVestedInvestment,\n vestedHarmonisedInvestment: this.state.rawVestedHarmonisedInvestment,\n savingsInvestment: this.state.rawSavingsInvestment, \n salaryValue: this.state.rawSalaryValue,\n withdrawalYear: this.state.withdrawalYear,\n formattedSavingsInvestment: this.state.savingsInvestment\n })\n \n\n // scroll to next slide\n const nextSlideIsOpen = document.querySelector('.slide-4') != null\n if (nextSlideIsOpen) { \n this.props.custScrollTo(document.querySelector('.slide-4'))\n } else { \n this.props.openNextSlide()\n }\n\n }\n }\n\n\n\n render() {\n const chevronSVG = \"data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8'%3f%3e %3csvg width='8px' height='6px' viewBox='0 0 8 6' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3ctitle%3eC3B35B76-2140-4AC7-8E67-7BEB0ECFAC23%3c/title%3e%3cg id='Home' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3e%3cg id='1920-Desktop-(1600)---Input-info-dropdown-open' transform='translate(-1341.000000%2c -558.000000)' fill='%2326B0E2'%3e%3cg id='input/default-copy' transform='translate(1074.000000%2c 553.000000)'%3e%3cg id='tooltip/default' transform='translate(271.000000%2c 8.196667) scale(1%2c -1) translate(-271.000000%2c -8.196667) translate(267.000000%2c 5.726667)'%3e%3cpolygon id='%f0%9f%8e%a8-icon-fill' points='7.06 0 4 3.05333333 0.94 0 0 0.94 4 4.94 8 0.94'%3e%3c/polygon%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/svg%3e\";\n return (\n \n
\n
\n
{ this.props.journey === 1 ? this.props.data?.slide3.title : this.props.data?.savingsComponent.slide3.title} \n\n
\n
\n\n
\n
\n
\n \n\n\n\n\n\n\n\n \n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`
Gender
${this.props.data?.slide3.tooltips.gender}
`}\n >\n
Gender \n
? \n \n
\n this.handleGender(0)} />\n \n Male\n \n
\n
\n this.handleGender(1)} />\n \n Female\n \n
\n
\n \n \n \n {this.props.journey === 1 &&\n
\n Have you made a withdrawal from your \n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`Savings component
${this.props.data?.slide3.tooltips.savingsComponent}
`} \n className='hover-none focus-none cursor-pointer'> \n savings component \n ? \n \n in the current tax year?\n \n }\n\n {this.props.journey === 2 &&\n\n \n Have you made a withdrawal from your \n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`Savings component
${this.props.data?.savingsComponent.slide3.tooltips.savingsComponent}
`} \n className='hover-none focus-none cursor-pointer'> \n savings component \n ? \n \n in the current tax year?\n \n }\n\n
\n this.handleWithdrawalYear(0)} />\n \n No\n \n
\n \n this.handleWithdrawalYear(1)}\n />\n \n Yes\n \n
\n \n \n \n\n \n \n
\n {this.props.journey === 1 &&\n <>\n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Reason for leaving your employer
${this.props.data?.slide3.tooltips.leavingEmployer}
`}\n >\n
Reason for leaving your employer \n
? \n \n
this.handleLeaveReason(e)}>\n {this.state.dropContent.map(option => (\n {option.text} \n ))}\n \n >\n }\n
\n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Annual taxable income
${this.props.data?.slide3.tooltips.taxableIncome}
`}\n className=\"hover-none focus-none cursor-pointer\">
annual taxable income \n ?\n \n
\n
\n
this.handleSalaryValue(e)}\n onInput={(e) => { e.target.classList.remove('has-error') }}\n\n // required validation message\n data-toggle=\"popover\"\n data-bs-template=\"
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"manual\"\n data-bs-placement=\"bottom\" \n data-bs-content=\"
Please enter an amount
\" \n onBlur={(e) => { this.handleSalaryValuePopUp(e) }} \n />\n
\n
\n\n\n \n \n\n {this.props.journey === 1 &&\n <>\n\n
\n Retirement component breakdown in your Umbrella Fund investment: \n
\n\n
\n
\n Component \n
\n
\n Amount \n
\n
\n\n >\n }\n\n
\n {this.props.journey === 1 &&\n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-trigger=\"focus\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Savings
${this.props.data?.slide3.tooltips.savingsComponent}
`}\n >\n
Savings \n
? \n \n
\n }\n {this.props.journey === 2 &&\n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-trigger=\"focus\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Savings component
${this.props.data?.savingsComponent.slide3.tooltips.savingsComponent}
`}\n className=\"hover-none focus-none cursor-pointer \">\n
Savings component \n
? \n \n amount \n \n
\n }\n \n this.handleInvestmentValue(e, 'rawSavingsInvestment', 'savingsInvestment')}\n onInput={(e) => { e.target.classList.remove('has-error') }}\n onBlur={(e) => this.handleWithdrawalYearBlur(this.state.withdrawalYear)}\n />\n
\n \n\n {this.props.journey === 1 &&\n \n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-trigger=\"focus\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Retirement
${this.props.data?.slide3.tooltips.retirementComponent}
`}\n >\n
Retirement \n
? \n \n
\n \n this.handleInvestmentValue(e, 'rawCurrentInvestment', 'currentInvestment')}\n onInput={(e) => { e.target.classList.remove('has-error') }}\n />\n
\n \n }\n\n {this.props.journey === 1 &&\n \n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-trigger=\"focus\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Vested
${this.props.data?.slide3.tooltips.vestedComponent}
`}\n >\n
Vested \n
? \n \n
\n \n this.handleInvestmentValue(e, 'rawVestedInvestment', 'vestedInvestment')}\n onInput={(e) => { e.target.classList.remove('has-error') }}\n />\n
\n \n }\n\n {this.props.journey === 1 &&\n \n
\"\n data-bs-html=\"true\"\n data-bs-placement=\"bottom\"\n data-trigger=\"focus\"\n data-bs-trigger=\"focus\"\n data-bs-content={`
Vested harmonised
${this.props.data?.slide3.tooltips.vestedHarmonisedComponent}
`}\n >\n
Vested harmonised \n
? \n \n
\n \n this.handleInvestmentValue(e, 'rawVestedHarmonisedInvestment', 'vestedHarmonisedInvestment')}\n onInput={(e) => { e.target.classList.remove('has-error') }}\n />\n
\n \n }\n\n\n\n\n\n {this.props.journey === 1 &&\n <>\n { this.toggleCollapse(); this.props.recordAnalytics(e); }}>\n Where can I find my retirement component breakdown? \n \n
\n\n \n
\n
You can find this breakdown of your Allan Gray Umbrella Fund accounts(s) on your:
\n
\n
\n
\n >\n }\n\n {this.props.journey === 2 &&\n <>\n { this.toggleCollapse(); this.props.recordAnalytics(e); }}>\n Where can I find my savings component amount? \n \n
\n\n \n
\n
You can find your current savings component amount in your retirement fund account on your:
\n
\n
\n
\n >\n }\n \n \n\n {this.state.withDrawalYearNextError &&\n \n }\n\n {this.state.withDrawalYearMinError &&\n \n }\n\n {this.state.withDrawalYearMinNote &&\n \n }\n\n \n\n
\n
\n
\n See my results \n
\n
\n
\n \n\n \n )\n }\n}\n\nexport default Slide3;\n","import React from 'react';\n\nclass Slide4 extends React.Component {\n constructor(props) {\n super(props);\n this.slide4 = React.createRef();\n this.handleScroll = this.handleScroll.bind(this);\n this.rangePopUpChangeHandler = this.rangePopUpChangeHandler.bind(this);\n this.rangePopUpInputHandler = this.rangePopUpInputHandler.bind(this);\n this.rangePopUpClickHandler = this.rangePopUpClickHandler.bind(this);\n this.ctaButtonHandler = this.ctaButtonHandler.bind(this);\n this.destroyExistingSliderIfExists = this.destroyExistingSliderIfExists.bind(this);\n this.minSavingsValue = 2000;\n this.currencyFormat = wNumb({\n decimals: 0,\n thousand: ' ',\n prefix: 'R'\n });\n this.state = {\n step: 500,\n visible: false,\n scrolling: false,\n graphData: {},\n popContent: ` \n
`,\n collapseOpen: false,\n vestedSliderValue: 0,\n savingsSliderValue: 0,\n savingsAboveMinState: true,\n maxPotentialTaxValue: 0\n };\n }\n componentDidMount() {\n this.props.custScrollTo(this.slide4.current)\n\n // init vested slider\n if (this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment > 0) {\n let slider = document.getElementById('slider-round');\n\n $('[data-toggle=\"popover\"]').popover();\n $(\".fade\").addClass(\"in\");\n $(document).on(\"click\", \".popover .slide3__popover-cancel\", function () {\n $(this).parents(\".popover\").popover('hide');\n });\n\n\n\n const rangeSetup = {}\n rangeSetup['min'] = [0, 1];\n rangeSetup['max'] = this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment;\n\n \n this.destroyExistingSliderIfExists(slider);\n noUiSlider.create(slider, {\n start: 0,\n connect: [true, false],\n range: rangeSetup\n });\n slider.noUiSlider.on('update', (values, handle, unencoded, tap, positions, noUiSlider) => this.setValue(values, positions));\n slider.noUiSlider.on('change', () => {\n gtag('event', 'Slider - Moved', {\n 'event_category': 'Preservation calculator',\n 'event_label': 'Vested Slider - Adjust the slider',\n });\n });\n }\n\n\n // init savings slider\n if (this.props.formData.savingsInvestment > 0 || this.props.formData.formattedSavingsInvestment !== '') {\n let sliderSavings = document.getElementById('slider-round-savings');\n\n // need to convert the actual savings value to 1 if it's 0 for slider to not be (rightfully) weird\n let savingsInvestmentNonZeroValue = this.props.formData.savingsInvestment > 0 ? this.props.formData.savingsInvestment : 1;\n\n const rangeSetupSavings = {}\n\n // savings amount equal or more than min (R2000) \n let savingsAboveMin = this.props.formData.savingsInvestment >= this.minSavingsValue;\n\n\n // if have withdrawn in current tax year\n if (this.props.formData.withdrawalYear === 1) {\n rangeSetupSavings['min'] = [0, 1];\n rangeSetupSavings['max'] = savingsInvestmentNonZeroValue;\n\n // if savings below than min, withdraw all or nothing\n if(!savingsAboveMin){ \n rangeSetupSavings['min'] = [0, savingsInvestmentNonZeroValue];\n\n // if savings is 0, disable slider\n if(this.props.formData.savingsInvestment === 0){\n sliderSavings.closest('.slider-styled-wrap').classList.add('is-disabled');\n }\n }\n \n\n // if savings above min, disable slider\n if (savingsAboveMin) { \n sliderSavings.closest('.slider-styled-wrap').classList.add('is-disabled');\n }\n }\n\n // if have not withdrawn this tax year\n if (this.props.formData.withdrawalYear === 0) {\n \n\n // if savings above min, first step starts at min (R2000)\n if (savingsAboveMin) { \n let minRangeStepPercent = (this.minSavingsValue / savingsInvestmentNonZeroValue * 100) + '%';\n rangeSetupSavings['min'] = [0, this.minSavingsValue];\n rangeSetupSavings[minRangeStepPercent] = [this.minSavingsValue, 1]; \n rangeSetupSavings['max'] = savingsInvestmentNonZeroValue; \n }\n\n // if savings below min, disable slider\n if (!savingsAboveMin) { \n rangeSetupSavings['min'] = [0, savingsInvestmentNonZeroValue]; \n rangeSetupSavings['max'] = savingsInvestmentNonZeroValue; \n sliderSavings.closest('.slider-styled-wrap').classList.add('is-disabled');\n }\n\n }\n\n \n\n // attach popovers\n this.setState({ savingsAboveMinState: savingsAboveMin }, () => {\n $('[data-toggle=\"popover\"]').popover();\n });\n\n \n this.destroyExistingSliderIfExists(sliderSavings);\n noUiSlider.create(sliderSavings, {\n start: 0,\n connect: [true, false],\n range: rangeSetupSavings\n });\n\n\n sliderSavings.noUiSlider.on('update', (values, handle, unencoded, tap, positions, noUiSlider) => {\n this.setSavingsValue(values, positions)\n });\n\n\n sliderSavings.noUiSlider.on('change', (values) => {\n gtag('event', 'Slider - Moved', {\n 'event_category': 'Preservation calculator',\n 'event_label': 'Savings Slider - Adjust the slider',\n });\n });\n }\n\n\n\n // on scroll\n window.addEventListener('scroll', this.handleScroll);\n this.handleMaxTax()\n }\n\n componentWillUnmount() {\n let slider = document.getElementById('slider-round');\n let sliderSavings = document.getElementById('slider-round-savings');\n if (slider) slider.noUiSlider.off();\n if (sliderSavings) sliderSavings.noUiSlider.off();\n window.removeEventListener('scroll', this.handleScroll);\n }\n\n destroyExistingSliderIfExists(slider){\n if(slider && slider.noUiSlider){\n slider.noUiSlider.destroy();\n }\n }\n\n rangePopUpClickHandler(e) {\n e.target.querySelector('input') && e.target.querySelector('input').focus();\n }\n\n rangePopUpChangeHandler(e, sliderId) {\n let slider = document.getElementById(sliderId);\n const inputValue = this.currencyFormat.from(e.target.value);\n slider.noUiSlider.set(inputValue);\n }\n\n rangePopUpInputHandler(e) {\n // get start custor pos\n const startCursorPos = e.target.selectionStart\n const startLength = e.target.value.length;\n\n // formatting\n const inputValue = this.currencyFormat.from(e.target.value);\n const formattedVal = inputValue ? this.currencyFormat.to(inputValue) : 'R0';\n e.target.value = formattedVal;\n\n // set final cursor pos\n const endLength = formattedVal.length;\n const newCursorPos = endLength - startLength + startCursorPos;\n e.target.selectionStart = newCursorPos;\n e.target.selectionEnd = newCursorPos;\n }\n\n\n attachRangePopUp(id, value, position, text, sliderId) {\n let rangeV = document.getElementById(id);\n rangeV.innerHTML = ''; // clear it first to prevent blur issue, see: https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node\n rangeV.innerHTML = `\n ${text}\n \n \n `;\n rangeV.style.left = `calc(${position}% + 2px)`;\n rangeV.addEventListener('click', this.rangePopUpClickHandler);\n rangeV.querySelector('input').addEventListener('change', (e) => this.rangePopUpChangeHandler(e, sliderId), false);\n rangeV.querySelector('input').addEventListener('blur', (e) => this.rangePopUpChangeHandler(e, sliderId), false);\n rangeV.querySelector('input').addEventListener('input', this.rangePopUpInputHandler, false);\n\n }\n\n setValue(values, rawPosition) {\n let value = this.currencyFormat.from(values[0]);\n let position = rawPosition[0];\n\n this.attachRangePopUp('rangeV', value, position, this.props.data?.slide4?.rangeText, 'slider-round');\n\n this.setState({ vestedSliderValue: value });\n\n this.calcHeight(value, this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment - value,\n this.state.savingsSliderValue, this.props.formData.savingsInvestment - this.state.savingsSliderValue)\n }\n\n setSavingsValue(values, rawPosition) {\n let value = this.currencyFormat.from(values[0]);\n let position = rawPosition[0];\n let label = this.props.journey === 1 ? this.props.data?.slide4?.rangeSavingsText : this.props.data?.savingsComponent?.slide4?.rangeSavingsText;\n\n this.attachRangePopUp('rangeV-savings', value, position, label, 'slider-round-savings');\n\n this.setState({ savingsSliderValue: value });\n\n this.calcHeight(\n this.state.vestedSliderValue,\n this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment - this.state.vestedSliderValue,\n value,\n this.props.formData.savingsInvestment - value\n )\n }\n\n handleScroll() {\n let view = this.slide4.current.getBoundingClientRect();\n const Buffer = 5\n if (view.top <= Buffer) this.setState({ visible: true });\n if (this.state.visible && (view.top >= window.innerHeight / 2)) {\n this.props.closeSlide();\n }\n\n // On certain devices the user is able to scroll up and change the input values without triggering the previous step scroll, mostly long mobile devices\n // On this step it is required to reset the graph\n const inputrect = document.getElementById('savingsBalance').getBoundingClientRect()\n if (this.state.visible && inputrect.top > 0) {\n this.props.closeSlide();\n }\n } \n\n getVestedWithdrawValue(amount){\n let table = this.props.formData.leavingReason == 3 ?\n this.props.data?.slide4?.retrenchmentTable\n : this.props.data?.slide4?.retireDismissalTable\n\n\n // Calculate tax values on vested\n var taxKeys = Object.keys(table);\n taxKeys = taxKeys.reverse();\n let calcedTaxValue = 0;\n let totalValueRemaining = amount;\n for (var i = 0; i < taxKeys.length; i++) {\n\n if (totalValueRemaining > taxKeys[i]) {\n let taxableAmount = (totalValueRemaining - parseInt(taxKeys[i]))\n calcedTaxValue = calcedTaxValue + taxableAmount * (table[taxKeys[i]] / 100);\n totalValueRemaining = totalValueRemaining - taxableAmount;\n //break;\n }\n }\n\n return calcedTaxValue;\n }\n\n\n\n getSavingsTaxValue(amount = 0){\n\n let salaryValue = this.props.formData.salaryValue;\n let savingsTaxTable = this.props.data?.slide4.individualTaxTable;\n let savingsTaxKeys = Object.keys(savingsTaxTable);\n savingsTaxKeys = savingsTaxKeys.reverse();\n let calcedSavingsTaxValue = 0;\n let totalValueRemaining = salaryValue + amount;\n\n for (var i = 0; i < savingsTaxKeys.length; i++) {\n if (totalValueRemaining > savingsTaxKeys[i]) {\n let taxableAmount = (totalValueRemaining - parseInt(savingsTaxKeys[i]));\n calcedSavingsTaxValue = calcedSavingsTaxValue + taxableAmount * (savingsTaxTable[savingsTaxKeys[i]] / 100);\n totalValueRemaining = totalValueRemaining - taxableAmount; \n }\n }\n\n \n\n return calcedSavingsTaxValue;\n } \n\n\n handleMaxTax() {\n\n // calculates max potential tax, on...\n let maxPotentialTaxValue = 0; \n\n // calculate max tax on vested\n let investedValue = this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment;\n maxPotentialTaxValue += this.getVestedWithdrawValue(investedValue); \n\n // calculate max tax values on savings\n // max tax = tax with full savings amount less tax without savings amount\n maxPotentialTaxValue += this.getSavingsTaxValue(this.props.formData.savingsInvestment) - this.getSavingsTaxValue(0); \n\n this.setState({ maxPotentialTaxValue: maxPotentialTaxValue });\n\n }\n \n\n calcHeight(vestedWithdrawingValue, vestedRemainingValue, savingsWithdrawingValue, savingsRemainingValue) {\n\n // calculate tax on vested withdrawal\n let calcedTaxValue = this.getVestedWithdrawValue(vestedWithdrawingValue);\n\n // calculate tax values on savings withdrawal\n // tax = tax with withdrawal amount less tax without withdrawal amount\n let calcedSavingsTaxValue = this.getSavingsTaxValue(savingsWithdrawingValue) - this.getSavingsTaxValue(0);\n\n\n // calculate genderWithdraw\n let genderTable = this.props.data?.slide4?.drawdowns;\n var genderKeys = Object.keys(genderTable);\n var gender = this.props.formData.gender === 0 ? \"male\" : \"female\";\n genderKeys = genderKeys.sort().reverse();\n let selectedBracket = null;\n genderKeys.forEach(key => {\n if (selectedBracket == null && this.props.formData.retireAge >= parseInt(key)) {\n selectedBracket = key;\n }\n });\n\n let yearsInvested = this.props.formData.retireAge - this.props.formData.currentAge;\n\n // growth on remaining value\n let growth = (vestedRemainingValue + savingsRemainingValue) * Math.pow(1.1, yearsInvested) - (vestedRemainingValue + savingsRemainingValue);\n\n // max potential future growth\n let maxFutureGrowth = ((this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment + this.props.formData.savingsInvestment) * Math.pow(1.1, yearsInvested)) - (this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment + this.props.formData.savingsInvestment);\n\n // added: maximum potential monthly value\n let maxPotentialMonthlyIncome = (this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment + this.props.formData.savingsInvestment + maxFutureGrowth) * parseFloat(genderTable[selectedBracket][gender]) * 0.01 / 12;\n\n\n // For potential growth result\n let maxTaxableValue = vestedWithdrawingValue + savingsWithdrawingValue + vestedRemainingValue + savingsRemainingValue;\n\n let output = {\n\n // withdrawing value (from vested)\n withdrawingValue: vestedWithdrawingValue + savingsWithdrawingValue,\n\n // tax value on withdrawal amount\n taxValue: calcedTaxValue + calcedSavingsTaxValue,\n\n // withdrawal amount less tax \n reciveValue: (vestedWithdrawingValue + savingsWithdrawingValue) - (calcedTaxValue + calcedSavingsTaxValue),\n\n // total invested less withdrawal amount\n remainingValue: vestedRemainingValue + savingsRemainingValue,\n\n // monthly income after withdrawal\n monthlyValue: (vestedRemainingValue + savingsRemainingValue + growth) * parseFloat(genderTable[selectedBracket][gender]) * 0.01 / 12,\n\n // monthy income after withdrawal (in today's money)\n monthlyNegInflation: (((vestedRemainingValue + savingsRemainingValue + growth) * parseFloat(genderTable[selectedBracket][gender]) * 0.01) / 12) / Math.pow(1 + 0.06, yearsInvested),\n\n // total value after withdrawal\n valueAtRetirement: growth + vestedRemainingValue + savingsRemainingValue,\n\n // updated: max potential future growth\n maxFutureGrowth: maxFutureGrowth,\n\n // added: maximum potential monthly value\n maxPotentialMonthlyIncome: maxPotentialMonthlyIncome,\n\n\n // For potential growth result \n growValue: growth,\n growthHeight: ((vestedRemainingValue + savingsRemainingValue) / maxTaxableValue * 100) + \"%\",\n }\n\n\n // potential monthly graph percentage\n output.potentialMonthlyIncomeHeight = (output.monthlyValue / maxPotentialMonthlyIncome * 100) + \"%\";\n\n this.setState({\n graphData: output,\n popContent: ` \n Your potential monthly retirement income
\n R${this.addDigitSpaces(output.monthlyValue)}
\n ${this.props.journey === 1 ? this.props.data?.slide4.tooltips.potentialIncome : this.props.data?.savingsComponent.slide4.tooltips.potentialIncome}
\n R${this.addDigitSpaces(output.monthlyNegInflation)}
\n ${this.props.journey === 1 ? this.props.data?.slide4.tooltips.potentialIncomeToday : this.props.data?.savingsComponent.slide4.tooltips.potentialIncomeToday}
`\n })\n return (output)\n }\n\n toggleCollapse() {\n this.setState({ collapseOpen: !this.state.collapseOpen })\n }\n\n addDigitSpaces(item) {\n let value = parseFloat(item).toFixed(0);\n return value.replace(/\\B(?=(\\d{3})+(?!\\d))/g, \" \");\n }\n\n ctaButtonHandler() {\n const nextSlideIsOpen = document.querySelector('.slide-5') != null\n if (nextSlideIsOpen) {\n this.props.custScrollTo(document.querySelector('.slide-5'))\n } else {\n this.props.openNextSlide()\n }\n }\n\n render() {\n return (\n \n
\n
\n
{ this.props.journey === 1 ? this.props.data?.slide4.title : this.props.data?.savingsComponent.slide4.title} \n
\n
\n
\n
\n\n {this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment > 0 &&\n
\n
\n
\n
\n
R0 \n
\n
R{this.addDigitSpaces(this.props.formData.vestedInvestment + this.props.formData.vestedHarmonisedInvestment)} \n
\n
\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`
Tax information
${this.props.data?.slide4.tooltips.taxInfoVested}
`}\n >\n
Tax information \n
? \n \n
\n
\n }\n \n {(this.props.formData.savingsInvestment > 0 || this.props.formData.formattedSavingsInvestment !== '') &&\n \n
\n
\n
\n
R0 \n
\n
R{this.addDigitSpaces(this.props.formData.savingsInvestment)} \n
\n
\n
\n\n\n {!this.state.savingsAboveMinState && this.props.formData.withdrawalYear === 1 && \n <>\n {this.props.formData.savingsInvestment !== 0 &&\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`
Tax information
${this.props.data?.slide4.tooltips.taxInfoSavings}
`}\n >\n
Tax information \n
? \n \n
\n }\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`
Why is this slider limited?
${this.props.data?.slide4.tooltips.sliderlimitedInfo}
`}\n >\n
Why is this slider limited \n
? \n \n
\n >\n\n }\n\n {this.state.savingsAboveMinState && this.props.formData.withdrawalYear === 0 && \n\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`Tax information
${this.props.data?.slide4.tooltips.taxInfoSavings}
`}\n >\n Tax information \n ? \n \n\n }\n\n\n {this.state.savingsAboveMinState && this.props.formData.withdrawalYear === 1 &&\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`Why am I unable to withdraw?
${this.props.data?.slide4.tooltips.disabledAboveMin}
`}\n >\n Why am I unable to withdraw \n ? \n \n }\n\n {!this.state.savingsAboveMinState && this.props.formData.withdrawalYear === 0 &&\n\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`Why am I unable to withdraw?
${this.props.data?.slide4.tooltips.disabledBelowMin}
`}\n >\n Why am I unable to withdraw \n ? \n \n }\n\n\n \n \n }\n\n \n\n
\n
\n
\n
\n
The total value you have selected to preserve could grow to: R{this.addDigitSpaces(this.state.graphData.valueAtRetirement)}
\n\n {/* potential growth */}\n\n
\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={this.state.popContent}\n data-analytics-label=\"Pres tool link – Monthly retirement income\"\n data-analytics-action=\"Link – Clicked\"\n data-analytics-category=\"Preservation calculator\"\n onClick={(e) => { this.props.recordAnalytics(e); }}\n >\n
Your potential monthly retirement income \n
? \n \n \n\n\n {/* potential growth */} \n
Remaining invested for your future
\n\n {/* potential growth */}\n
\n Potential growth: R{this.addDigitSpaces(this.state.graphData.growValue)} \n
\n\n {/* potential monthly\n
The money you keep invested could grow to the value above. This could provide you with the monthly retirement income below in addition to the income you will receive from your retirement component.
\n */}\n\n {/* potential monthly\n
Potential additional retirement income: R\n {this.addDigitSpaces(this.state.graphData.monthlyValue)}\n
\n */}\n\n\n
Maximum
\n
\n
\n
R0
\n
\n\n {/* potential growth */}\n
\n\n {/* potential monthly\n
\n */}\n
\n
\n \n Maximum\n \n \n \n {/* potential growth */}\n R{this.addDigitSpaces(this.state.graphData.maxFutureGrowth)}\n\n {/* potential monthly\n R{this.addDigitSpaces(this.state.graphData.maxPotentialMonthlyIncome)}\n */}\n \n
\n
\n
\n
Amount you keep invested: R{this.addDigitSpaces(this.state.graphData.remainingValue)}
\n
\n
\n
\n
\n
\n
\n
Withdrawing for now
\n
\n
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content={`
Tax
${this.props.journey === 1 ? this.props.data?.slide4.tooltips.taxWithdrawal : this.props.data?.savingsComponent.slide4.tooltips.taxWithdrawal}
`}\n >\n
Tax \n
? \n you could pay on your withdrawal:
R{this.addDigitSpaces(this.state.graphData.taxValue)} \n
\n
\n
R0
\n
\n
R{this.addDigitSpaces(this.state.maxPotentialTaxValue)}
\n
\n
\n
Withdrawal amount after tax: R{this.addDigitSpaces(this.state.graphData.reciveValue)}
\n
\n
\n
\n \n
\n Important information about these numbers ? \n
\n
\n
\n \n
\n
\n
\n this.ctaButtonHandler()}>Find out more about my options \n
\n
\n
\n \n \n {/* Info numbers popup modal */}\n \n
\n
\n
\n
Important information about these numbers \n \n \n
\n
\n
\n
\n \n )\n }\n}\n\nexport default Slide4;\n\n","import React from 'react';\n\nclass Slide5 extends React.Component {\n constructor(props) {\n super(props);\n this.slide5 = React.createRef();\n this.handleScroll = this.handleScroll.bind(this);\n this.visible = false;\n this.state = {\n selected: 1\n };\n }\n\n componentDidMount() {\n this.props.custScrollTo(this.slide5.current)\n this.setCarousels();\n window.addEventListener('scroll', this.handleScroll);\n }\n\n componentWillUnmount() {\n window.removeEventListener('scroll', this.handleScroll);\n } \n\n handleScroll() {\n let view = this.slide5.current.getBoundingClientRect();\n const Buffer = 5\n if (view.top <= Buffer) this.visible = true;\n if (this.visible && (view.top >= window.innerHeight / 2)) {\n this.props.closeSlide();\n }\n }\n toggleActive(newtabId) {\n switch (newtabId) {\n case 0:\n this.props.toggleTab(5.1)\n this.setState({ selected: 0 })\n break;\n case 1:\n this.props.toggleTab(5.2)\n this.setState({ selected: 1 })\n break;\n case 2:\n this.props.toggleTab(5.3)\n this.setState({ selected: 2 })\n break;\n default:\n break;\n }\n }\n componentDidUpdate() {\n\n this.unsetCarousels();\n this.setCarousels();\n \n }\n\n unsetCarousels() {\n $('.slide5-0__carousel').filter('.slick-initialized').slick('unslick');\n $('.slide5-0__mobile-carousel').filter('.slick-initialized').slick('unslick');\n $('.slide5-1__carousel').filter('.slick-initialized').slick('unslick');\n $('.slide5-1__mobile-carousel').filter('.slick-initialized').slick('unslick');\n $('.slide5-2__carousel').filter('.slick-initialized').slick('unslick');\n $('.slide5-2__mobile-carousel').filter('.slick-initialized').slick('unslick');\n }\n\n setCarousels() {\n\n $('[data-toggle=\"popover\"]').popover()\n\n $('.pres-carousel').on('beforeChange', function (event, slick, currentSlide, nextSlide) {\n gtag('event', 'Chevron - Clicked', {\n 'event_category': 'Preservation calculator',\n 'event_label': 'Chevron – Arrow ' + (nextSlide > currentSlide ? '>' : '<') + ' click',\n });\n });\n\n $('.pres-carousel').not('.slick-initialized').slick({\n slidesToShow: 1,\n arrows: true,\n dots: true,\n nextArrow: \"Next \",\n prevArrow: \"Previous \"\n });\n\n\n }\n\n getScreenWidth() {\n return window.innerWidth;\n }\n render() {\n return (\n \n\n\n {this.props.journey === 1 &&\n <>\n\n
\n
\n
\n
this.toggleActive(0)}>\n {this.getScreenWidth() <= 578 ? \"Transfer\" : \"Transfer your investment\"}\n
\n
\n
\n
this.toggleActive(1)}>\n Remain invested\n
\n
\n
\n
this.toggleActive(2)}>\n {this.getScreenWidth() <= 578 ? \"Withdraw\" : \"Withdraw from your investment\"}\n
\n
\n
\n {this.state.selected === 0 &&
\n {/*Mobile carousel*/}\n
\n
\n
Tap the icons for more information
\n
\n
\n {this.props.data?.slide5?.transfer?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n {/*Desktop list*/}\n
\n {this.props?.data?.slide5?.transfer?.iconList?.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n
\n
\n {this.props.data?.slide5?.transfer?.carousel.map((card, index) => (\n
\n
Things to keep in mind \n
{card.subheading}
\n
\n
\n ))}\n
\n
\n
\n
\n If you do not wish to remain in your Umbrella Retirement Fund investment but want to remain invested, you can transfer your investment to the
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content=\"
\n
Allan Gray Pension or Provident Preservation Fund
You can transfer your retirement savings in your Umbrella Retirement Fund account to an Allan Gray Preservation Fund account to preserve and grow your money until you retire. The rules around accessing your money will remain in place, but different investment fees apply. However, you cannot add to your retirement savings in a preservation fund. If you want to continue adding to your retirement savings, you can separately start another investment, such as a retirement annuity. Alternatively, you can transfer your investment to the Allan Gray Retirement Annuity, but note that you will sacrifice your ability to make a withdrawal, as the rules of the product are different to the Umbrella Retirement Fund.
\">\n
Allan Gray Pension or Provident Preservation Fund \n
? \n . The minimum lump sum required to transfer to a different Allan Gray product is R50 000.\n \n
\n You may also move to a retirement product offered by another financial services provider or transfer to your new employer’s retirement fund.\n
\n
\n
\n
\n
\n
\n If you do not wish to remain in your Umbrella Retirement Fund investment but want to remain invested, you can transfer your investment to the
\"\n data-bs-html=\"true\"\n data-bs-trigger=\"focus\"\n data-bs-placement=\"bottom\"\n data-bs-content=\"
\n
Allan Gray Pension or Provident Preservation Fund
You can transfer your retirement savings in your Umbrella Retirement Fund account to an Allan Gray Preservation Fund account to preserve and grow your money until you retire. The rules around accessing your money will remain in place, but different investment fees apply. However, you cannot add to your retirement savings in a preservation fund. If you want to continue adding to your retirement savings, you can separately start another investment, such as a retirement annuity. Alternatively, you can transfer your investment to the Allan Gray Retirement Annuity, but note that you will sacrifice your ability to make a withdrawal, as the rules of the product are different to the Umbrella Retirement Fund.
\">\n
Allan Gray Pension or Provident Preservation Fund \n
? \n . The minimum lump sum required to transfer to a different Allan Gray product is R50 000.\n \n
\n You may also move to a retirement product offered by another financial services provider or transfer to your new employer’s retirement fund.\n
\n
\n
\n \n }\n {this.state.selected === 1 && \n {/*Mobile carousel*/}\n
\n
\n
Tap the icons for more information
\n
\n
\n {this.props.data?.slide5?.remainInvested?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n {/*Mobile carousel end*/}\n {/*Desktop list*/}\n
\n {this.props.data?.slide5?.remainInvested?.iconList?.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n
\n
\n {this.props.data?.slide5?.remainInvested?.carousel?.map((card, index) => (\n
\n
Things to keep in mind \n
{card.subheading}
\n
\n
\n ))}\n
\n
\n
\n
Your Allan Gray Online account lets you: \n
\n Update your contact details and nominees \n View and manage your investments securely \n Avoid printing, signing and emailing forms \n \n
\n
\n
\n
\n
\n
Your Allan Gray Online account lets you: \n
\n Update your contact details and nominees \n View and manage your investments securely \n Avoid printing, signing and emailing forms \n \n
\n
\n
\n
\n
}\n {this.state.selected === 2 && \n\n {/*Mobile carousel*/}\n
\n
\n
Reasons this option may not be suitable for you: \n \n
\n
Tap the icons for more information
\n
\n
\n {this.props.data?.slide5?.withdraw?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n {/*Desktop list*/}\n
\n
Reasons this option may not be suitable for you: \n \n
\n {this.props.data?.slide5?.withdraw?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n
\n
\n {this.props.data?.slide5?.withdraw?.carousel.map((card, index) => (\n
\n
Things to keep in mind \n
{card.subheading}
\n
\n
\n ))}\n
\n
\n {/*Desktop */}\n\n
\n
Keep as much as you can invested
\n
\n
{ this.props.goToSlide4(); this.props.recordAnalytics(e); }}>See what happens if you withdraw a portion. \n
\n
\n {/*Mobile */}\n
\n
\n
Keep as much as you can invested
\n
\n
{ this.props.goToSlide4(); this.props.recordAnalytics(e); }}>See what happens if you withdraw a portion. \n
\n
\n\n
\n\n
}\n >\n }\n\n {this.props.journey === 2 &&\n <>\n \n \n\n
\n
this.toggleActive(1)}>\n Remain invested\n
\n
\n
\n
this.toggleActive(2)}>\n {this.getScreenWidth() <= 578 ? \"Withdraw\" : \"Withdraw from your investment\"}\n
\n
\n
\n {this.state.selected === 1 && \n {/*Mobile carousel*/}\n
\n
\n
Tap the icons for more information
\n
\n
\n {this.props.data?.savingsComponent.slide5?.remainInvested?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n {/*Mobile carousel end*/}\n {/*Desktop list*/}\n
\n {this.props.data?.savingsComponent.slide5?.remainInvested?.iconList?.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n
\n
\n {this.props.data?.savingsComponent.slide5?.remainInvested?.carousel?.map((card, index) => (\n
\n
Things to keep in mind \n
{card.subheading}
\n
\n
\n ))}\n
\n
\n
\n
Your Allan Gray Online account lets you: \n
\n Update your contact details and nominees \n View and manage your investments securely \n Avoid printing, signing and emailing forms \n \n
\n
\n
\n
\n
\n
Your Allan Gray Online account lets you: \n
\n Update your contact details and nominees \n View and manage your investments securely \n Avoid printing, signing and emailing forms \n \n
\n
\n
\n
\n
}\n {this.state.selected === 2 && \n\n {/*Mobile carousel*/}\n
\n
\n
Reasons this option may not be suitable for you: \n \n
\n
Tap the icons for more information
\n
\n
\n {this.props.data?.savingsComponent.slide5?.withdraw?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n {/*Desktop list*/}\n
\n
Reasons this option may not be suitable for you: \n \n
\n {this.props.data?.savingsComponent.slide5?.withdraw?.iconList.map((item, index) => (\n
\n
\n
\n
\n
\n
\n\n
\n
\n
\n ))}\n
\n
\n
\n
\n {this.props.data?.savingsComponent.slide5?.withdraw?.carousel.map((card, index) => (\n
\n
Things to keep in mind \n
{card.subheading}
\n
\n
\n ))}\n
\n
\n {/*Desktop */}\n\n
\n
Keep as much as you can invested
\n
\n
{ this.props.goToSlide4(); this.props.recordAnalytics(e); }}>See what happens if you withdraw a portion. \n
\n
\n {/*Mobile */}\n
\n
\n
Keep as much as you can invested
\n
\n
{ this.props.goToSlide4(); this.props.recordAnalytics(e); }}>See what happens if you withdraw a portion. \n
\n
\n\n
\n\n
}\n >\n }\n\n\n\n\n\n \n \n
\n
\n
\n \n {this.props?.data?.copyrightLink} \n
\n
\n
\n
\n \n )\n }\n}\n\nexport default Slide5;\n\n","import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport DOMPurify from 'dompurify';\n\nimport Slide1 from './slides/slide1';\nimport Slide2 from './slides/slide2';\nimport Slide3 from './slides/slide3';\nimport Slide4 from './slides/slide4';\nimport Slide5 from './slides/slide5';\n\n'use strict';\nvar serverData;\nconst serverDataURL = document.getElementById('preservation-calculator').getAttribute('data-apiURL');\nconst journeyParam = document.getElementById('preservation-calculator').getAttribute('data-journey');\n\n\nclass App extends React.Component {\n constructor(props) {\n super(props); \n this.custScrollTo = this.custScrollTo.bind(this);\n this.mainNavOffsetHandler = this.mainNavOffsetHandler.bind(this);\n this.MOBILE_NAV_BREAKPOINT = 768;\n this.isMobile = window.matchMedia(\"(max-width: 767px)\").matches; \n this.journey = parseInt(journeyParam) || 1; // 1 for exit journey (default), 2 for savings component journey\n this.state = { \n step: 1,\n loading: true,\n data: serverData,\n goToSlide4: false,\n formValues: {\n currentAge: 0,\n retireAge: 0,\n gender: 0,\n leavingReason: 0,\n currentInvestment: 0,\n vestedInvestment: 0,\n savingsInvestment: 0\n }\n };\n }\n\n componentDidMount() {\n\n // begin at first step on reload\n this.toggleSlide(1);\n\n this.isMobile = window.matchMedia(\"(max-width: 767px)\").matches; \n\n // get data & set loading state to false on success\n $.getJSON(serverDataURL) \n .done((data) => {\n this.setState({\n data: data,\n loading: false\n });\n window.scroll(0, this.isMobile ? 77 : 130);\n })\n .fail((jqxhr, textStatus, error) => {\n var err = textStatus + \", \" + error;\n console.log(\"Server data request failed: \" + err);\n\n $.getJSON('data/fakeServerData.json') \n .done((data) => {\n this.setState({\n data: data,\n loading: false\n });\n window.scroll(0, this.isMobile ? 77 : 130);\n })\n .fail(function (jqxhr, textStatus, error) {\n var err = textStatus + \", \" + error;\n console.log(\"Fallback data request failed: \" + err);\n });\n });\n \n window.dataLayer = window.dataLayer || [];\n window.addEventListener('scroll', this.mainNavOffsetHandler);\n }\n\n recordAnalytics(e) {\n\n gtag('event', e.currentTarget.getAttribute('data-analytics-action'), {\n 'event_category': e.currentTarget.getAttribute('data-analytics-category'),\n 'event_label': e.currentTarget.getAttribute('data-analytics-label'),\n });\n }\n\n toggleSlide(slideNum, isBulletNav = false) { \n\n // do nothing if slide # not yet unlocked AND is bullet nav \n if (slideNum > this.state.step && isBulletNav) {\n return\n }\n\n switch (slideNum) {\n case 1:\n this.setStepHandler(1);\n window.location.href = '#step-1';\n break;\n case 2:\n this.setStepHandler(2);\n window.location.href = '#step-2';\n break;\n case 3:\n this.setStepHandler(3);\n window.location.href = this.journey === 2 ? '#step-2' : '#step-3'; \n break;\n case 4:\n this.setStepHandler(4);\n window.location.href = this.journey === 2 ? '#step-3' : '#step-4' \n break;\n case 5.1:\n this.setStepHandler(5);\n window.location.href = this.journey === 2 ? '#step-4-Transfer' : '#step-5-Transfer';\n break;\n case 5.2:\n this.setStepHandler(5);\n window.location.href = this.journey === 2 ? '#step-4-Remain' : '#step-5-Remain'; \n break;\n case 5.3:\n this.setStepHandler(5);\n window.location.href = this.journey === 2 ? '#step-4-Withdraw' : '#step-5-Withdraw'; \n break;\n default:\n break;\n }\n\n // if usabilla survey active, send virtual pageview\n try {\n window.usabilla_live(\"virtualPageView\");\n }\n catch (err) {\n console.log('Unable to trigger usabilla virtual pageview');\n }\n\n gtag('event', 'page_view', {\n page_title: 'Preservation tool: ' + window.location.hash.slice(1),\n page_path: window.location.href\n });\n\n }\n goToSlide4() {\n this.setState({ goToSlide4: true, step: 4 })\n window.location.href = '#step-4';\n }\n\n clearSlide4Scroll() {\n this.setState({ goToSlide4: false })\n }\n\n getStepStyling(stepNum) {\n if (this.state.step === stepNum) {\n return \"active\"\n }\n }\n\n setFormState(value) {\n this.setState({ formValues: value })\n }\n\n setStepHandler(num) {\n if (num === undefined) {\n return\n }\n this.setState({ step: num });\n }\n\n removePtags(textFromServer) {\n if (textFromServer.slice(0, 3) == \"\") {\n return textFromServer.substr(3, textFromServer.length - 7)\n }\n return textFromServer;\n }\n\n sanitizeHTML(dirtyHTML){\n return DOMPurify.sanitize(dirtyHTML, { ADD_ATTR: ['target']})\n }\n\n mainNavOffsetHandler() {\n if (window.pageYOffset || document.documentElement.scrollTop) {\n document.body.classList.remove('is-top');\n } else {\n document.body.classList.add('is-top');\n }\n }\n\n custScrollTo(element) { \n element.scrollIntoView({ behavior: \"smooth\", block: \"start\", inline: \"nearest\" });\n }\n\n\n render() {\n const tickSVG = \"data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8'%3f%3e %3csvg width='12px' height='12px' viewBox='0 0 12 12' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3ctitle%3e6B537FDF-5163-4F55-9CE8-0FC7B0450613%3c/title%3e%3cg id='Home' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3e%3cg id='1920-Desktop-(1600)---Input-dropdown-open' transform='translate(-241.000000%2c -279.000000)'%3e%3cg id='Group' transform='translate(235.000000%2c 185.000000)'%3e%3cg id='stepper/increment/large-copy-2' transform='translate(0.000000%2c 88.000000)'%3e%3cg id='done_black_24dp' transform='translate(6.000000%2c 6.000000)'%3e%3cpolygon id='Path' points='0 0 12 0 12 12 0 12'%3e%3c/polygon%3e%3cpolygon id='Path' fill='%23B2B2B4' fill-rule='nonzero' points='4.5 8.1 2.4 6 1.7 6.7 4.5 9.5 10.5 3.5 9.8 2.8'%3e%3c/polygon%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/svg%3e\";\n return (\n
\n {!this.state.loading &&\n
\n\n
\n\n\n {this.journey === 1 &&\n
\n }\n\n\n
\n\n
\n\n
\n
\n }\n {!this.state.loading && this.state.step > 0 &&
this.removePtags(text)}\n sanitizeHTML = {(html) => this.sanitizeHTML(html)}\n openNextSlide={() => this.journey === 1 ? this.toggleSlide(2) : this.toggleSlide(3)} // skip slide 2 if savings journey\n custScrollTo={(el) => this.custScrollTo(el)}\n recordAnalytics={(e) => this.recordAnalytics(e)}\n />}\n {!this.state.loading && this.journey === 1 && this.state.step > 1 && this.sanitizeHTML(html)} \n closeSlide={() => this.toggleSlide(1)}\n openNextSlide={() => this.toggleSlide(3)}\n custScrollTo={(el) => this.custScrollTo(el)}\n recordAnalytics={(e) => this.recordAnalytics(e)}\n />}\n {!this.state.loading && this.state.step > 2 && this.sanitizeHTML(html)}\n closeSlide={() => this.journey === 1 ? this.toggleSlide(2) : this.toggleSlide(1)} // return to slide 1 if savings journey\n openNextSlide={() => this.toggleSlide(4)}\n setFormValues={(value) => this.setFormState(value)}\n custScrollTo={(el) => this.custScrollTo(el)}\n recordAnalytics={(e) => this.recordAnalytics(e)}\n setStepHandler={(num) => this.setStepHandler(num)}\n />}\n {!this.state.loading && this.state.step > 3 && this.sanitizeHTML(html)}\n goToSlide4={this.state.goToSlide4}\n clearSlide4Scroll={() => clearSlide4Scroll()}\n closeSlide={() => this.toggleSlide(3)}\n openNextSlide={() => this.toggleSlide(5.2)}\n formData={this.state.formValues}\n custScrollTo={(el) => this.custScrollTo(el)}\n recordAnalytics={(e) => this.recordAnalytics(e)}\n />}\n {!this.state.loading && this.state.step > 4 && this.removePtags(text)} \n sanitizeHTML = {(html) => this.sanitizeHTML(html)} \n closeSlide={() => this.toggleSlide(4)}\n goToSlide4={() => this.goToSlide4()}\n toggleTab={(value) => this.toggleSlide(value)}\n custScrollTo={(el) => this.custScrollTo(el)}\n recordAnalytics={(e) => this.recordAnalytics(e)}\n />}\n \n )\n }\n}\n\nlet domContainer = document.querySelector('#preservation-calculator');\nconst root = createRoot(domContainer);\nroot.render(\n \n \n \n);"],"names":["module","exports","entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","fun","thisValue","args","Func","arrayForEach","unapply","Array","prototype","forEach","arrayPop","pop","arrayPush","push","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","objectHasOwnProperty","hasOwnProperty","regExpTest","RegExp","test","typeErrorCreate","func","TypeError","_len2","arguments","length","_key2","thisArg","_len","_key","addToSet","set","array","transformCaseFunc","undefined","l","element","lcElement","cleanArray","index","clone","object","newObject","property","value","isArray","constructor","lookupGetter","prop","desc","get","html$1","svg$1","svgFilters","svgDisallowed","mathMl$1","mathMlDisallowed","text","html","svg","mathMl","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","EXPRESSIONS","__proto__","NODE_TYPE","getGlobal","window","createDOMPurify","DOMPurify","root","version","removed","document","nodeType","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","Element","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","createHTMLDocument","IS_ALLOWED_URI$1","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","ALLOWED_URI_REGEXP","ADD_TAGS","ADD_ATTR","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","elm","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHook","entryPoint","currentNode","data","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","__removalCount","parent","parentTagName","Boolean","_checkValidNamespace","expr","_isValidAttribute","lcTag","lcName","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","attr","forceKeepAttr","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","hookFunction","removeHook","removeHooks","removeAllHooks","factory","aa","ca","p","a","b","c","encodeURIComponent","da","Set","ea","fa","ha","add","ia","ja","ka","la","ma","v","d","e","f","g","this","acceptsBooleans","attributeName","attributeNamespace","mustUseProperty","propertyName","type","sanitizeURL","removeEmptyString","z","split","ra","sa","toUpperCase","ta","slice","pa","isNaN","qa","oa","xlinkHref","ua","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","va","Symbol","for","wa","ya","za","Aa","Ba","Ca","Da","Ea","Fa","Ga","Ha","Ia","Ja","iterator","Ka","La","A","assign","Ma","Error","stack","Na","Oa","prepareStackTrace","defineProperty","h","k","displayName","includes","Pa","render","Qa","$$typeof","_context","_payload","_init","Ra","Sa","Ta","Va","_valueTracker","getValue","setValue","stopTracking","Ua","Wa","checked","Xa","activeElement","Ya","defaultChecked","defaultValue","_wrapperState","initialChecked","Za","initialValue","controlled","ab","bb","cb","db","eb","fb","options","selected","defaultSelected","disabled","gb","dangerouslySetInnerHTML","children","hb","ib","jb","kb","lb","mb","nb","valueOf","MSApp","execUnsafeLocalFunction","ob","lastChild","nodeValue","pb","animationIterationCount","aspectRatio","borderImageOutset","borderImageSlice","borderImageWidth","boxFlex","boxFlexGroup","boxOrdinalGroup","columnCount","columns","flex","flexGrow","flexPositive","flexShrink","flexNegative","flexOrder","gridArea","gridRow","gridRowEnd","gridRowSpan","gridRowStart","gridColumn","gridColumnEnd","gridColumnSpan","gridColumnStart","fontWeight","lineClamp","lineHeight","opacity","order","orphans","tabSize","widows","zIndex","zoom","fillOpacity","floodOpacity","stopOpacity","strokeDasharray","strokeDashoffset","strokeMiterlimit","strokeOpacity","strokeWidth","qb","rb","sb","style","setProperty","keys","charAt","substring","tb","menuitem","area","base","br","col","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","ub","vb","is","wb","xb","target","srcElement","correspondingUseElement","yb","zb","Ab","Bb","Cb","stateNode","Db","Eb","Fb","Gb","Hb","Ib","Jb","Kb","Lb","Mb","addEventListener","removeEventListener","Nb","m","onError","Ob","Pb","Qb","Rb","Sb","Tb","Vb","alternate","return","flags","Wb","memoizedState","dehydrated","Xb","Zb","child","sibling","current","Yb","$b","ac","unstable_scheduleCallback","bc","unstable_cancelCallback","cc","unstable_shouldYield","dc","unstable_requestPaint","B","unstable_now","ec","unstable_getCurrentPriorityLevel","fc","unstable_ImmediatePriority","gc","unstable_UserBlockingPriority","hc","unstable_NormalPriority","ic","unstable_LowPriority","jc","unstable_IdlePriority","kc","lc","oc","Math","clz32","pc","qc","log","LN2","rc","sc","tc","uc","pendingLanes","suspendedLanes","pingedLanes","entangledLanes","entanglements","vc","xc","yc","zc","Ac","eventTimes","Cc","C","Dc","Ec","Fc","Gc","Hc","Ic","Jc","Kc","Lc","Mc","Nc","Oc","Map","Pc","Qc","Rc","Sc","delete","pointerId","Tc","nativeEvent","blockedOn","domEventName","eventSystemFlags","targetContainers","Vc","Wc","priority","isDehydrated","containerInfo","Xc","Yc","dispatchEvent","shift","Zc","$c","ad","bd","cd","ReactCurrentBatchConfig","dd","ed","transition","fd","gd","hd","id","Uc","stopPropagation","jd","kd","ld","md","nd","od","keyCode","charCode","pd","qd","rd","_reactName","_targetInst","currentTarget","isDefaultPrevented","defaultPrevented","returnValue","isPropagationStopped","preventDefault","cancelBubble","persist","isPersistent","wd","xd","yd","sd","eventPhase","bubbles","cancelable","timeStamp","Date","now","isTrusted","td","ud","view","detail","vd","Ad","screenX","screenY","clientX","clientY","pageX","pageY","ctrlKey","shiftKey","altKey","metaKey","getModifierState","zd","button","buttons","relatedTarget","fromElement","toElement","movementX","movementY","Bd","Dd","dataTransfer","Fd","Hd","animationName","elapsedTime","pseudoElement","Id","clipboardData","Jd","Ld","Md","Esc","Spacebar","Left","Up","Right","Down","Del","Win","Menu","Apps","Scroll","MozPrintableKey","Nd","Od","Alt","Control","Meta","Shift","Pd","Qd","key","fromCharCode","code","location","repeat","locale","which","Rd","Td","width","height","pressure","tangentialPressure","tiltX","tiltY","twist","pointerType","isPrimary","Vd","touches","targetTouches","changedTouches","Xd","Yd","deltaX","wheelDeltaX","deltaY","wheelDeltaY","wheelDelta","deltaZ","deltaMode","Zd","$d","ae","be","documentMode","ce","de","ee","fe","ge","he","ie","le","color","date","datetime","email","month","number","password","range","search","tel","time","url","week","me","ne","oe","event","listeners","pe","qe","re","se","te","ue","ve","we","xe","ye","ze","oninput","Ae","detachEvent","Be","Ce","attachEvent","De","Ee","Fe","He","Ie","Je","Ke","offset","nextSibling","Le","contains","compareDocumentPosition","Me","HTMLIFrameElement","contentWindow","href","Ne","contentEditable","Oe","focusedElem","selectionRange","start","end","selectionStart","selectionEnd","min","defaultView","getSelection","extend","rangeCount","anchorNode","anchorOffset","focusNode","focusOffset","createRange","setStart","removeAllRanges","addRange","setEnd","left","scrollLeft","top","scrollTop","focus","Pe","Qe","Re","Se","Te","Ue","Ve","We","animationend","animationiteration","animationstart","transitionend","Xe","Ye","Ze","animation","$e","af","bf","cf","df","ef","ff","gf","hf","lf","mf","concat","nf","Ub","instance","listener","D","of","has","pf","qf","rf","random","sf","bind","capture","passive","n","t","J","u","w","F","tf","uf","parentWindow","vf","wf","na","xa","$a","ba","je","char","ke","unshift","xf","yf","zf","Af","Bf","Cf","Df","Ef","__html","Ff","setTimeout","Gf","clearTimeout","Hf","Promise","Jf","queueMicrotask","resolve","then","catch","If","Kf","Lf","Mf","previousSibling","Nf","Of","Pf","Qf","Rf","Sf","Tf","Uf","E","G","Vf","H","Wf","Xf","Yf","contextTypes","__reactInternalMemoizedUnmaskedChildContext","__reactInternalMemoizedMaskedChildContext","Zf","childContextTypes","$f","ag","bg","getChildContext","cg","__reactInternalMemoizedMergedChildContext","dg","eg","fg","gg","hg","jg","kg","lg","mg","ng","og","pg","qg","rg","sg","tg","ug","vg","wg","xg","yg","I","zg","Ag","Bg","elementType","deletions","Cg","pendingProps","overflow","treeContext","retryLane","Dg","mode","Eg","Fg","Gg","memoizedProps","Hg","Ig","Jg","Kg","Lg","defaultProps","Mg","Ng","Og","Pg","Qg","Rg","_currentValue","Sg","childLanes","Tg","dependencies","firstContext","lanes","Ug","Vg","context","memoizedValue","next","Wg","Xg","Yg","interleaved","Zg","$g","ah","updateQueue","baseState","firstBaseUpdate","lastBaseUpdate","shared","pending","effects","bh","ch","eventTime","lane","payload","callback","dh","K","eh","fh","gh","q","r","y","hh","ih","jh","Component","refs","kh","nh","isMounted","_reactInternals","enqueueSetState","L","lh","mh","enqueueReplaceState","enqueueForceUpdate","oh","shouldComponentUpdate","isPureReactComponent","ph","contextType","state","updater","qh","componentWillReceiveProps","UNSAFE_componentWillReceiveProps","rh","props","getDerivedStateFromProps","getSnapshotBeforeUpdate","UNSAFE_componentWillMount","componentWillMount","componentDidMount","sh","ref","_owner","_stringRef","th","join","uh","vh","wh","xh","yh","zh","Ah","done","Bh","Ch","Dh","Eh","Fh","Gh","Hh","Ih","Jh","Kh","Lh","M","Mh","revealOrder","Nh","Oh","_workInProgressVersionPrimary","Ph","ReactCurrentDispatcher","Qh","Rh","N","O","P","Sh","Th","Uh","Vh","Q","Wh","Xh","Yh","Zh","$h","ai","bi","ci","baseQueue","queue","di","ei","fi","lastRenderedReducer","action","hasEagerState","eagerState","lastRenderedState","dispatch","gi","hi","ii","ji","ki","getSnapshot","li","mi","R","ni","lastEffect","stores","oi","pi","qi","ri","destroy","deps","si","ti","ui","vi","wi","xi","yi","zi","Ai","Bi","Ci","Di","Ei","Fi","Gi","Hi","Ii","Ji","readContext","useCallback","useContext","useEffect","useImperativeHandle","useInsertionEffect","useLayoutEffect","useMemo","useReducer","useRef","useState","useDebugValue","useDeferredValue","useTransition","useMutableSource","useSyncExternalStore","useId","unstable_isNewReconciler","identifierPrefix","Ki","message","digest","Li","Mi","error","Ni","WeakMap","Oi","Pi","Qi","Ri","getDerivedStateFromError","componentDidCatch","Si","componentStack","Ti","pingCache","Ui","Vi","Wi","Xi","ReactCurrentOwner","Yi","Zi","$i","aj","bj","compare","cj","dj","ej","baseLanes","cachePool","transitions","fj","gj","hj","ij","jj","UNSAFE_componentWillUpdate","componentWillUpdate","componentDidUpdate","kj","lj","pendingContext","mj","Aj","Bj","Cj","Dj","nj","oj","pj","fallback","qj","rj","tj","dataset","dgst","uj","vj","_reactRetry","sj","subtreeFlags","wj","xj","isBackwards","rendering","renderingStartTime","last","tail","tailMode","yj","Ej","S","Fj","Gj","wasMultiple","multiple","suppressHydrationWarning","onClick","onclick","size","createElementNS","autoFocus","T","Hj","Ij","Jj","Kj","U","Lj","WeakSet","V","Mj","W","Nj","Oj","Qj","Rj","Sj","Tj","Uj","Vj","Wj","_reactRootContainer","Xj","X","Yj","Zj","ak","onCommitFiberUnmount","componentWillUnmount","bk","ck","dk","ek","fk","isHidden","gk","hk","display","ik","jk","kk","lk","__reactInternalSnapshotBeforeUpdate","src","Wk","mk","ceil","nk","ok","pk","Y","Z","qk","rk","sk","tk","uk","Infinity","vk","wk","xk","yk","zk","Ak","Bk","Ck","Dk","Ek","callbackNode","expirationTimes","expiredLanes","wc","callbackPriority","ig","Fk","Gk","Hk","Ik","Jk","Kk","Lk","Mk","Nk","Ok","Pk","finishedWork","finishedLanes","Qk","timeoutHandle","Rk","Sk","Tk","Uk","Vk","mutableReadLanes","Bc","Pj","onCommitFiberRoot","mc","onRecoverableError","Xk","onPostCommitFiberRoot","Yk","Zk","al","isReactComponent","pendingChildren","bl","mutableSourceEagerHydrationData","cl","cache","pendingSuspenseBoundaries","el","fl","gl","hl","il","jl","zj","$k","ll","reportError","ml","_internalRoot","nl","ol","pl","ql","sl","rl","unmount","unstable_scheduleHydration","splice","querySelectorAll","JSON","stringify","form","tl","usingClientEntryPoint","Events","ul","findFiberByHostInstance","bundleType","rendererPackageName","vl","rendererConfig","overrideHookState","overrideHookStateDeletePath","overrideHookStateRenamePath","overrideProps","overridePropsDeletePath","overridePropsRenamePath","setErrorHandler","setSuspenseHandler","scheduleUpdate","currentDispatcherRef","findHostInstanceByFiber","findHostInstancesForRefresh","scheduleRefresh","scheduleRoot","setRefreshHandler","getCurrentFiber","reconcilerVersion","__REACT_DEVTOOLS_GLOBAL_HOOK__","wl","isDisabled","supportsFiber","inject","createPortal","dl","createRoot","unstable_strictMode","findDOMNode","flushSync","hydrate","hydrateRoot","hydratedSources","_getVersion","_source","unmountComponentAtNode","unstable_batchedUpdates","unstable_renderSubtreeIntoContainer","checkDCE","err","setState","forceUpdate","__self","__source","escape","_status","_result","default","Children","map","count","toArray","only","Fragment","Profiler","PureComponent","StrictMode","Suspense","cloneElement","createContext","_currentValue2","_threadCount","Provider","Consumer","_defaultValue","_globalName","createFactory","createRef","forwardRef","isValidElement","lazy","memo","startTransition","unstable_act","sortIndex","performance","setImmediate","startTime","expirationTime","priorityLevel","navigator","scheduling","isInputPending","MessageChannel","port2","port1","onmessage","postMessage","unstable_Profiling","unstable_continueExecution","unstable_forceFrameRate","floor","unstable_getFirstCallbackNode","unstable_next","unstable_pauseExecution","unstable_runWithPriority","delay","unstable_wrapCallback","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","getter","__esModule","definition","o","obj","Slide1","React","super","ctaButtonHandler","$","popover","on","parents","querySelector","journey","custScrollTo","openNextSlide","className","bannerText","savingsComponent","bannerImageUrl","sanitizeHTML","contentTitle","descriptionText","ctaButtonText","removePtags","copyrightText","copyrightLink","tabIndex","popUpText","Slide2","slide2","handleScroll","open","visible","$slide2Carousel","filter","slick","centerMode","initialSlide","slidesToShow","infinite","arrows","dots","variableWidth","nextArrow","prevArrow","getBoundingClientRect","innerHeight","closeSlide","getScreenWidth","innerWidth","title","introText","slide2Cards","card","isDefault","imgSrc","alt","imgAlt","headingText","descText","slide2Cta","Slide3","slide3","disableIosTextFieldZoom","minSavingsValue","savingsInputTimer","collapseOpen","currentAge","retireAge","leavingReason","gender","withdrawalYear","rawCurrentInvestment","rawVestedInvestment","rawVestedHarmonisedInvestment","rawSavingsInvestment","currentInvestment","vestedInvestment","vestedHarmonisedInvestment","savingsInvestment","rawSalaryValue","salaryValue","withDrawalYearNextError","withDrawalYearMinError","withDrawalYearMinNote","withDrawlYearEagerValidation","formValid","bsTemplate","dropContent","addClass","customSelect","jcf","setOptions","wrapNative","wrapNativeOnMobile","fakeDropInBody","maxVisibleItems","toggleCollapse","userAgent","MSStream","handleInvestmentValue","rawInvestmentVar","investmentVar","withDrawalYearEagerValidation","handleWithdrawalYear","val","startCursorPos","startLength","validationCheck","parseFloat","toFixed","formattedVal","newCursorPos","handleSalaryValue","handleCurrentAge","classList","handleCurrentAgePopUp","bootstrap","Popover","getInstance","getElementById","hide","show","once","handleLeaveReason","handleGender","handleWithdrawalYearBlur","handleRetireAge","handleRetireAgePopUp","handleSalaryValuePopUp","isFormValid","handleForm","setFormValues","formattedSavingsInvestment","chevronSVG","autoComplete","onSubmit","noValidate","htmlFor","onChange","onInput","onBlur","max","placeholder","tooltips","leavingEmployer","option","taxableIncome","spellCheck","retirementComponent","vestedComponent","vestedHarmonisedComponent","role","recordAnalytics","validation","Slide4","slide4","rangePopUpChangeHandler","rangePopUpInputHandler","rangePopUpClickHandler","destroyExistingSliderIfExists","currencyFormat","wNumb","decimals","thousand","prefix","step","scrolling","graphData","popContent","vestedSliderValue","savingsSliderValue","savingsAboveMinState","maxPotentialTaxValue","formData","slider","rangeSetup","noUiSlider","connect","values","handle","unencoded","tap","positions","gtag","sliderSavings","savingsInvestmentNonZeroValue","rangeSetupSavings","savingsAboveMin","closest","minRangeStepPercent","setSavingsValue","handleMaxTax","off","sliderId","inputValue","to","attachRangePopUp","position","rangeV","rawPosition","rangeText","calcHeight","label","rangeSavingsText","inputrect","getVestedWithdrawValue","amount","retrenchmentTable","retireDismissalTable","taxKeys","reverse","calcedTaxValue","totalValueRemaining","taxableAmount","parseInt","getSavingsTaxValue","savingsTaxTable","individualTaxTable","savingsTaxKeys","calcedSavingsTaxValue","investedValue","vestedWithdrawingValue","vestedRemainingValue","savingsWithdrawingValue","savingsRemainingValue","genderTable","drawdowns","genderKeys","sort","selectedBracket","yearsInvested","growth","pow","maxFutureGrowth","maxPotentialMonthlyIncome","maxTaxableValue","output","withdrawingValue","taxValue","reciveValue","remainingValue","monthlyValue","monthlyNegInflation","valueAtRetirement","growValue","growthHeight","potentialMonthlyIncomeHeight","addDigitSpaces","potentialIncome","potentialIncomeToday","item","taxInfoVested","taxInfoSavings","sliderlimitedInfo","disabledAboveMin","disabledBelowMin","taxWithdrawal","popUpNumbersText","Slide5","slide5","setCarousels","toggleActive","newtabId","toggleTab","unsetCarousels","currentSlide","nextSlide","not","contactLinkText","transfer","iconList","backText","carousel","subheading","ctaUrl","cta","remainInvested","educationText","rel","withdraw","goToSlide4","ctaSecondaryUrl","ctaSecondary","serverDataURL","journeyParam","App","mainNavOffsetHandler","MOBILE_NAV_BREAKPOINT","isMobile","matchMedia","loading","serverData","formValues","toggleSlide","getJSON","scroll","fail","jqxhr","textStatus","dataLayer","slideNum","isBulletNav","setStepHandler","usabilla_live","page_title","hash","page_path","clearSlide4Scroll","getStepStyling","stepNum","setFormState","num","textFromServer","substr","dirtyHTML","pageYOffset","scrollIntoView","behavior","block","inline","tickSVG","domContainer"],"sourceRoot":""}