{ "version": 3, "sources": ["../../RLP_Apps/src/wp/wp-login.tsx", "../../RLP_Apps/node_modules/apprun/src/app.ts", "../../RLP_Apps/node_modules/apprun/src/vdom-my.ts", "../../RLP_Apps/node_modules/apprun/src/web-component.ts", "../../RLP_Apps/node_modules/apprun/src/decorator.ts", "../../RLP_Apps/node_modules/apprun/src/directive.ts", "../../RLP_Apps/node_modules/apprun/src/component.ts", "../../RLP_Apps/node_modules/apprun/src/router.ts", "../../RLP_Apps/node_modules/apprun/src/apprun.ts", "../../RLP_Apps/node_modules/apprun/src/vdom.ts", "../../RLP_Apps/node_modules/jwt-decode/lib/atob.js", "../../RLP_Apps/node_modules/jwt-decode/lib/base64_url_decode.js", "../../RLP_Apps/node_modules/jwt-decode/lib/index.js", "../../RLP_Apps/src/fetch.ts", "../../RLP_Apps/src/api.ts", "../../RLP_Apps/src/dict.json.ts", "../../RLP_Apps/src/l10n.ts", "../../RLP_Apps/src/wp/login-views.tsx"], "sourcesContent": ["/* eslint-disable no-irregular-whitespace */\nimport app, { Component } from 'apprun';\nimport { auth, serializeObject, users } from '../api';\n\nimport _, { lang, setLanguage } from '../l10n';\nimport { LoginView, ResetPasswordView } from './login-views';\n\nexport function getCookie(name: string): string {\n const nameLenPlus = name.length + 1;\n return (\n document.cookie\n .split(';')\n .map(c => c.trim())\n .filter((cookie) => {\n return cookie.substring(0, nameLenPlus) === `${name}=`;\n })\n .map((cookie) => {\n return decodeURIComponent(cookie.substring(nameLenPlus));\n })[0] || null\n );\n}\n\ndeclare let $;\n\nenum Language {\n en = 0,\n fr = 1,\n}\n\ninterface IState {\n lang: Language;\n error: {\n msg: string;\n detail: string;\n };\n isLoading: boolean;\n redirectUrl: string;\n lightBoxValue: boolean;\n forgotPasswordStep1: boolean;\n forgotPasswordStep2: boolean;\n forgotPasswordStep3: boolean;\n noEmailAddressProvided: boolean;\n recoveryEmail?: string;\n maskedRecoveryEmail?: string;\n validStep2: boolean;\n showResetPasswordView: boolean;\n //passwordMatched: boolean;\n resetPasswordForm: IResetPassword;\n passwordChanged: boolean;\n}\n\ninterface IResetPassword {\n emailAddress: string;\n hashCode: string;\n password: string;\n confirmPassword: string;\n}\n\nexport default class LoginComponent extends Component {\n state: IState = {\n lang: window['initialLanguage'] | Language[lang],\n error: { msg: '', detail: '' },\n isLoading: false,\n redirectUrl: '',\n lightBoxValue: false,\n forgotPasswordStep1: false,\n forgotPasswordStep2: false,\n forgotPasswordStep3: false,\n noEmailAddressProvided: false,\n recoveryEmail: '',\n validStep2: false,\n showResetPasswordView: false,\n // passwordMatched : false,\n resetPasswordForm: { emailAddress: '', hashCode: '', password: '', confirmPassword: '' },\n passwordChanged: false,\n };\n\n view = (state: IState) => {\n let logoImage, logoImageFooter, textMessage, helpContent;\n if (state.lang) {\n //fr\n logoImage = '_html:\"Royal';\n logoImageFooter =\n '_html:

\"Royal';\n textMessage =\n '_html: Acc\u00E9der aux meilleurs outils de l\\'industrie, con\u00E7u pour maximiser votre potentiel de revenus. Apprendre davantage.';\n\n helpContent = ` Si vous avez un compte courriel Royal LePage, votre code d'utilisateur est votre adresse courriel, par exemple,\u00A0\"xxxxx@royallepage.ca\".\n Si vous n'avez pas un compte Royal LePage, veuillez contacter votre bureau ou notre Centre d'assistance \u00E0 la client\u00E8le.\n Si vous avez besoin d'aide, veuillez nous rejoindre par courriel \u00E0\u00A0aide@royallepage.ca\u00A0ou par t\u00E9l\u00E9phone au 1-877-757-4545. `;\n } else {\n //en\n logoImage = '_html:\"Royal';\n logoImageFooter =\n '_html:

\"Royal';\n textMessage =\n '_html: Access the industry\u2019s best resources: Designed to maximize your earning potential. Learn more.';\n\n helpContent = `If you have an active Royal LePage email account, your username is your address, i.e.\u00A0xxxxx@royallepage.ca.\n If you do not have a Royal LePage email address, please contact your office or Customer Care to confirm your username.\n If you have any questions or need help, contact us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545. `;\n }\n\n return (\n \n
\n \n
\n\n \n\n
\n
\n

\n {'_html:' + _('WELCOME') + '. ' + _('LOG IN TO') + ' ' + _('rlpNetworkTM') + '.'}\n

\n
\n \n \n {_('System Status')}\n \n
\n
\n\n \n
\n
\n
\n \n
\n
\n
\n
\n
\n

{_('Help')}

\n

{helpContent}

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

{_('Forgot Password Step 1')}

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

{_('Email Address/User Name not provided')}

\n
\n

\n {' '}\n {_(\n 'If you do not know your Royal LePage email address, please contact your office or Customer Care to confirm your email address. If you need assistance resetting your password, please contact Customer Care. You can reach us by emailing help@royallepage.ca or calling us at 1-877-757-4545.'\n )}\n

\n
\n
\n this.run('retrieveRecoveryEmail', $('#fpEmailAddress').val())}\n class=\"btn btn-rlp btn-block text-uppercase\">\n \n {_('Continue')}\n \n
\n
\n this.run('toggleFlag', 'state.forgotPasswordStep1', e)}\n class=\"btn btn-rlp btn-rlp-inverse btn-block text-uppercase\">\n \n {_('Cancel')}\n \n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n \n
\n
\n {state.validStep2 && (\n
\n
\n
\n

{_('Forgot Password Step 2')}

\n \n
{state.maskedRecoveryEmail}
\n

\n {_(\n 'If you no longer have access to the recovery email on file, you will need to contact Customer Care. You can reach us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545.'\n )}\n

\n
\n
\n this.run('sendFPInstructions')}\n class=\"btn btn-rlp btn-block text-uppercase\">\n \n {_('Send')}\n \n
\n
\n this.run('toggleFlag', 'state.forgotPasswordStep2', e)}\n class=\"btn btn-rlp btn-rlp-inverse btn-block text-uppercase\">\n \n {_('Cancel')}\n \n
\n
\n
\n
\n
\n )}\n {!state.validStep2 && (\n
\n
\n
\n

{_('Forgot Password Step 2')}

\n

\n {_(\n 'You do not have a recovery email on file. Please contact Customer Care. You can reach us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545.'\n )}\n

\n
\n
\n this.run('toggleFlag', 'state.forgotPasswordStep2', e)}\n class=\"btn btn-rlp btn-block text-uppercase\">\n \n {_('Cancel')}\n \n
\n
\n
\n
\n
\n )}\n
\n
\n
\n \n\n \n
\n
\n
\n \n
\n
\n
\n
\n
\n

{_('Forgot Password Step 3')}

\n

\n {_('Password reset instructions has been sent to ')} {state.maskedRecoveryEmail}.\n

\n

\n {_(\n 'Remember: Changing your password here will require you to change your email password on all of your devices.'\n )}\n

\n
\n
\n this.run('toggleFlag', 'state.forgotPasswordStep3', e)}\n class=\"btn btn-rlp btn-block text-uppercase\">\n \n {_('Go to Login Page')}\n \n
\n
\n
\n
\n
\n
\n
\n
\n \n\n {state.showResetPasswordView ? (\n \n ) : (\n \n )}\n\n
\n
\n \n
\n
\n
\n
{logoImageFooter}
\n
\n
\n \n
\n
\n \n
\n
\n
\n\n
\n
\n
\n {'_html:' + _('Royal LePage\u00AE is a registered trademark of Royal Bank of Canada and is used under licence by Bridgemarq Real Estate Services\u00AE. View important disclosures and notices about trademarks at rlp.ca/notices.')}\n
\n
\n
\n
\n {state.lang === 1 ? : }\n
\n
\n
\n
\n
\n
\n
\n
\n \n );\n };\n\n update = {\n lightBoxValue: (state: IState) => {\n if (state.lightBoxValue) {\n state.lightBoxValue = false;\n //console.log(\"this value is false and setting it to false\")\n } else {\n state.lightBoxValue = true;\n //console.log(\"this value is true and setting it to true\")\n }\n return state;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n toggleFlag: (state: IState, fieldToCheck, e: any = {}) => {\n e.preventDefault();\n const exp = fieldToCheck + ' = !' + fieldToCheck; //toggle the value\n // //console.log(exp);\n eval(exp);\n return state;\n },\n retrieveRecoveryEmail: async (state: IState, fpEmailAddress) => {\n //console.log(fpEmailAddress);\n //get recovery email\n if (!fpEmailAddress) {\n state.forgotPasswordStep2 = false;\n state.forgotPasswordStep1 = true;\n state.forgotPasswordStep3 = false;\n state.noEmailAddressProvided = true;\n } else {\n state.noEmailAddressProvided = false;\n const user = await users.getRecoveryEmail(fpEmailAddress);\n if (user) {\n //mask part of email\n if (user.recoveryEmail) {\n state.recoveryEmail = user.recoveryEmail;\n state.maskedRecoveryEmail = this.maskEmailAddress(user.recoveryEmail);\n state.validStep2 = true;\n } else {\n state.validStep2 = false;\n }\n //console.log(state.recoveryEmail);\n } else {\n state.validStep2 = false;\n }\n\n state.forgotPasswordStep2 = true;\n state.forgotPasswordStep1 = false;\n state.forgotPasswordStep3 = false;\n }\n return state;\n },\n sendFPInstructions: async (state: IState) => {\n //TODO : send to Notification service\n const sendResult = await users.sendForgotPasswordInstructions(state.recoveryEmail);\n\n //let sendResult = true;\n if (sendResult) {\n state.forgotPasswordStep3 = true;\n state.forgotPasswordStep1 = false;\n state.forgotPasswordStep2 = false;\n }\n\n return state;\n },\n validatePassword: (state, e) => {\n const isValid = this.validPassword(e.target.value);\n if (!isValid) {\n state.error.msg = 'Invalid Password';\n state.error.detail = 'Invalid Password';\n } else {\n state.resetPasswordForm.password = e.target.value;\n state.error.msg = '';\n state.error.detail = '';\n }\n return state;\n },\n\n changePassword: async (state: IState, password, confirmPassword) => {\n if(!this.validPassword(password)) {\n //invalid password\n state.error.msg = 'Invalid password';\n state.error.detail = 'Invalid password';\n } else if (password !== confirmPassword) {\n state.error.msg = 'Password and Confirm Password do not match';\n state.error.detail = 'Password and Confirm Password do not match';\n } else {\n state.resetPasswordForm.password = password;\n state.resetPasswordForm.confirmPassword = confirmPassword;\n //send to backend to process\n const result = await users.resetPassword(state.resetPasswordForm);\n if (result === 0) {\n state.error.msg = 'Error resetting password';\n state.error.detail = 'Error resetting password';\n } else if (result === 2) {\n //invalid password\n state.error.msg = 'Invalid password';\n state.error.detail = 'Invalid password';\n } else {\n //TODO : auto sign-in\n state.error.msg = '';\n state.error.detail = '';\n state.passwordChanged = true;\n }\n }\n\n return state;\n },\n\n '#resetPassword': (state, emailAddress, hashCode) => {\n const params = new URLSearchParams(location.search);\n const language = params.get('lang')?.trim().replace('/', '') || '';\n\n if (language === '1') {\n state.lang = 1;\n setLanguage(Language[state.lang]);\n } else {\n state.lang = 0;\n setLanguage(Language[state.lang]);\n }\n\n state.resetPasswordForm.emailAddress = emailAddress;\n state.resetPasswordForm.hashCode = hashCode;\n // //console.log(emailAddress);\n // //console.log(hashCode);\n state.showResetPasswordView = true;\n return state;\n },\n '#logout': () => {\n auth.signOut();\n // document.location.href = '/wp-login.php?action=logout';\n document.location.href = '/login';\n },\n 'sign-in-loading': (state) => {\n state.isLoading = true;\n state.error.msg = '';\n return state;\n },\n 'sign-in': async (state, e) => {\n e.preventDefault();\n state.isLoading = false;\n\n try {\n const singInRetVal = await auth.signIn(serializeObject(e.target) as { email: string; password: string });\n if (singInRetVal === 'stop') { return; }\n\n const urlParams = new URLSearchParams(location.search);\n state.redirectUrl = urlParams.get('redirectUrl') || '';\n\n if (state.redirectUrl) {\n const cleaned = decodeURIComponent(urlParams.toString()).replace('redirectUrl=' + state.redirectUrl, '');\n state.redirectUrl = state.redirectUrl + (state.redirectUrl.includes('?') ? '&' : '?') + cleaned;\n state.redirectUrl = state.redirectUrl.replace('&&', '&');\n window.location.replace(state.redirectUrl);\n } else {\n window.location.replace(getCookie('pll_language') === 'fr' ? '/accueil' : '/');\n }\n } catch (error) {\n return {\n ...state,\n error: {\n msg: 'Login failed',\n detail: 'Invalid username or password'\n }\n };\n }\n return state;\n },\n 'resetpassword-sign-in': async (state: IState, e) => {\n state.isLoading = false;\n try {\n e.preventDefault();\n\n try {\n const payload = { email: state.resetPasswordForm.emailAddress, password: state.resetPasswordForm.password };\n await auth.signIn(payload);\n } catch (errors) {\n const error = { msg: 'Login failed', detail: 'Invalid username or password' };\n return { ...state, error };\n }\n // this.saveToken(session);\n\n if (getCookie('pll_language') === 'fr') { window.location.replace('/accueil'); } else { window.location.replace('/'); }\n } catch ({ error }) {\n return { ...state, error };\n }\n },\n\n // '#user': (state, user) => {\n // setToken(user ? user.token : null);\n // app['user'] = user;\n // },\n\n '#set-language': (state) => {\n state.lang = state.lang === Language.en ? Language.fr : Language.en; // 0,1 used by WordPress\n const _lang = Language[state.lang];\n setLanguage(_lang);\n return state;\n },\n 'google-sign-in': async (state, e) => {\n e.preventDefault();\n state.isLoading = true;\n state.error.msg = '';\n try {\n // Initiate Google sign-in with PKCE\n const singInRetVal = await auth.signInWithGoogle();\n // Note: No need to handle redirection here as signInWithGoogle will redirect to Google\n\n if (singInRetVal === 'stop') { return; }\n\n const urlParams = new URLSearchParams(location.search);\n state.redirectUrl = urlParams.get('redirectUrl') || '';\n\n if (state.redirectUrl) {\n const cleaned = decodeURIComponent(urlParams.toString()).replace('redirectUrl=' + state.redirectUrl, '');\n state.redirectUrl = state.redirectUrl + (state.redirectUrl.includes('?') ? '&' : '?') + cleaned;\n state.redirectUrl = state.redirectUrl.replace('&&', '&');\n window.location.replace(state.redirectUrl);\n } else {\n window.location.replace(getCookie('pll_language') === 'fr' ? '/accueil' : '/');\n }\n } catch (error) {\n state.isLoading = false;\n return {\n ...state,\n error: {\n msg: 'Google Sign In Failed',\n detail: 'Unable to initiate Google sign in'\n }\n };\n }\n return state;\n },\n\n 'new-pwd-changed':() => {\n // Get the current value of the password input\n const passwordInput = document.getElementById('password') as HTMLInputElement;\n const password = passwordInput.value;\n // Rule 1: Password must have at least 8 characters and it should not exceed 40 characters\n const rule1 = (password.length >= 8) && (password.length <= 40);\n // Rule 2: Password must contain at least one uppercase letter\n const rule2 = /[A-Z]/.test(password);\n // Rule 3: Password must contain at least one lowercase letter\n const rule3 = /[a-z]/.test(password);\n // Rule 4: Password must contain at least one digit\n const rule4 = /\\d/.test(password);\n // Rule 5: Password must contain at least one special character\n const rule5 = /[!@#$%^&*()\\-_=+{}[\\]|\\\\;:'\",.<>/?`~]/.test(password);\n // Rule 5: Password should match with confirm\n const rule6 = (password === (document.getElementById('confirmPassword') as HTMLInputElement).value);\n\n this.setPwdRruleStatus(rule1, 'rule1');\n this.setPwdRruleStatus(rule2, 'rule2');\n this.setPwdRruleStatus(rule3, 'rule3');\n this.setPwdRruleStatus(rule4, 'rule4');\n this.setPwdRruleStatus(rule5, 'rule5');\n this.setPwdRruleStatus(rule6, 'rule6');\n },\n\n // '#refresh-JWT': state => {\n // return;\n // }\n };\n\n setPwdRruleStatus = (rule, id) => {\n const el = document.getElementById(id);\n el.classList.remove((rule) ? 'text-danger' : 'text-success');\n el.classList.add((rule) ? 'text-success' : 'text-danger');\n\n const elIcon = document.getElementById(id+'Icon');\n elIcon.classList.remove((rule) ? 'fa-close' : 'fa-check');\n elIcon.classList.add((rule) ? 'fa-check' : 'fa-close');\n elIcon.style.color = (rule) ? 'green' : 'red';\n }\n\n // private saveToken(session) {\n // const { user } = session;\n // setToken(user ? user.token : null);\n // // try {\n // // session = JSON.parse(session);\n // // app.run('#user', session.user);\n // // } catch {}\n // }\n\n private maskEmailAddress(input) {\n let result = '';\n let maskUsername = '';\n const prefix = input.substring(0, input.lastIndexOf('@'));\n const postfix = input.substring(input.lastIndexOf('@'));\n for (let i = 0; i < prefix.length; i++) {\n if (i === 0 || i === prefix.length - 1) {\n maskUsername = maskUsername + prefix[i].toString();\n } else {\n maskUsername = maskUsername + '*';\n }\n }\n result = maskUsername + postfix;\n return result;\n }\n\n // rendered = (state) => {\n // let token = await authorization.loginWithJWT();\n // if (token) {\n // let email = AccessToken.getUserFromJWT().sub;\n // let session = {\n // user: {\n // token,\n // email,\n // },\n // };\n // this.saveToken(state, session);\n // }\n // };\n\n private validPassword(password) {\n // const re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,12}$/;\n const re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*()_+{}[\\]:;<>,.?/~'\";|=)]).{8,40}$/;\n return re.test(password) && !password.includes('royal1');\n }\n}\n\nnew LoginComponent().start('login-page');\n", "import { EventOptions} from './types'\nexport class App {\n\n private _events: Object;\n\n public start;\n public h;\n public createElement;\n public render;\n public Fragment;\n public webComponent;\n\n constructor() {\n this._events = {};\n }\n\n on(name: string, fn: (...args) => void, options: EventOptions = {}): void {\n this._events[name] = this._events[name] || [];\n this._events[name].push({ fn, options });\n }\n\n off(name: string, fn: (...args) => void): void {\n const subscribers = this._events[name] || [];\n\n this._events[name] = subscribers.filter((sub) => sub.fn !== fn);\n }\n\n find(name: string): any {\n return this._events[name];\n }\n\n run(name: string, ...args): number {\n const subscribers = this._events[name] || [];\n\n console.assert(subscribers && subscribers.length > 0, 'No subscriber for event: ' + name);\n\n // Update the list of subscribers by pulling out those which will run once.\n // We must do this update prior to running any of the events in case they\n // cause additional events to be turned off or on.\n this._events[name] = subscribers.filter((sub) => {\n return !sub.options.once;\n });\n\n subscribers.forEach((sub) => {\n const { fn, options } = sub;\n if (options.delay) {\n this.delay(name, fn, args, options);\n } else {\n fn.apply(this, args);\n }\n return !sub.options.once;\n });\n\n return subscribers.length;\n }\n\n once(name: string, fn, options: EventOptions = {}): void {\n this.on(name, fn, { ...options, once: true });\n }\n\n private delay(name, fn, args, options): void {\n if (options._t) clearTimeout(options._t);\n options._t = setTimeout(() => {\n clearTimeout(options._t);\n fn.apply(this, args);\n }, options.delay);\n }\n}\n\nconst AppRunVersions = 'AppRun-2';\nlet app: App;\nconst root = (typeof self === 'object' && self.self === self && self) ||\n (typeof global === 'object' && global.global === global && global)\nif (root['app'] && root['_AppRunVersions']) {\n app = root['app'];\n} else {\n app = new App();\n root['app'] = app;\n root['_AppRunVersions'] = AppRunVersions;\n}\nexport default app;\n", "import { VDOM, VNode } from './types';\nexport type Element = any; //HTMLElement | SVGSVGElement | SVGElement;\n\nexport function Fragment(props, ...children): any[] {\n return collect(children);\n}\n\nconst ATTR_PROPS = '_props';\n\nfunction collect(children) {\n const ch = [];\n const push = (c) => {\n if (c !== null && c !== undefined && c !== '' && c !== false) {\n ch.push((typeof c === 'function' || typeof c === 'object') ? c : `${c}`);\n }\n }\n children && children.forEach(c => {\n if (Array.isArray(c)) {\n c.forEach(i => push(i));\n } else {\n push(c);\n }\n });\n return ch;\n}\n\nexport function createElement(tag: string | Function | [], props?: {}, ...children) {\n const ch = collect(children);\n if (typeof tag === 'string') return { tag, props, children: ch };\n else if (Array.isArray(tag)) return tag; // JSX fragments - babel\n else if (tag === undefined && children) return ch; // JSX fragments - typescript\n else if (Object.getPrototypeOf(tag).__isAppRunComponent) return { tag, props, children: ch } // createComponent(tag, { ...props, children });\n else if (typeof tag === 'function') return tag(props, ch);\n else throw new Error(`Unknown tag in vdom ${tag}`);\n};\n\nconst keyCache = new WeakMap();\n\nexport const updateElement = render;\n\nexport function render(element: Element, nodes: VDOM, parent = {}) {\n // console.log('render', element, node);\n // tslint:disable-next-line\n if (nodes == null || nodes === false) return;\n\n nodes = createComponent(nodes, parent);\n\n const isSvg = element?.nodeName === \"SVG\";\n\n if (!element) return;\n if (Array.isArray(nodes)) {\n updateChildren(element, nodes, isSvg);\n } else {\n updateChildren(element, [nodes], isSvg);\n }\n}\n\nfunction same(el: Element, node: VNode) {\n // if (!el || !node) return false;\n const key1 = el.nodeName;\n const key2 = `${node.tag || ''}`;\n return key1.toUpperCase() === key2.toUpperCase();\n}\n\nfunction update(element: Element, node: VNode, isSvg: boolean) {\n if (node['_op'] === 3) return;\n // console.assert(!!element);\n isSvg = isSvg || node.tag === \"svg\";\n if (!same(element, node)) {\n element.parentNode.replaceChild(create(node, isSvg), element);\n return;\n }\n !(node['_op'] & 2) && updateChildren(element, node.children, isSvg);\n !(node['_op'] & 1) && updateProps(element, node.props, isSvg);\n}\n\nfunction updateChildren(element, children, isSvg: boolean) {\n const old_len = element.childNodes?.length || 0;\n const new_len = children?.length || 0;\n const len = Math.min(old_len, new_len);\n for (let i = 0; i < len; i++) {\n const child = children[i];\n if (child['_op'] === 3) continue;\n const el = element.childNodes[i];\n if (typeof child === 'string') {\n if (el.textContent !== child) {\n if (el.nodeType === 3) {\n el.nodeValue = child\n } else {\n element.replaceChild(createText(child), el);\n }\n }\n } else if (child instanceof HTMLElement || child instanceof SVGElement) {\n element.insertBefore(child, el);\n } else {\n const key = child.props && child.props['key'];\n if (key) {\n if (el.key === key) {\n update(element.childNodes[i], child, isSvg);\n } else {\n // console.log(el.key, key);\n const old = keyCache[key];\n if (old) {\n const temp = old.nextSibling;\n element.insertBefore(old, el);\n temp ? element.insertBefore(el, temp) : element.appendChild(el);\n }\n update(element.childNodes[i], child, isSvg);\n }\n } else {\n update(element.childNodes[i], child, isSvg);\n }\n }\n }\n\n let n = element.childNodes.length;\n while (n > len) {\n element.removeChild(element.lastChild);\n n--;\n }\n\n if (new_len > len) {\n const d = document.createDocumentFragment();\n for (let i = len; i < children.length; i++) {\n d.appendChild(create(children[i], isSvg));\n }\n element.appendChild(d);\n }\n}\n\nfunction createText(node) {\n if (node?.indexOf('_html:') === 0) { // ?\n const div = document.createElement('div');\n div.insertAdjacentHTML('afterbegin', node.substring(6))\n return div;\n } else {\n return document.createTextNode(node??'');\n }\n}\n\nfunction create(node: VNode | string | HTMLElement | SVGElement, isSvg: boolean): Element {\n // console.assert(node !== null && node !== undefined);\n if ((node instanceof HTMLElement) || (node instanceof SVGElement)) return node;\n if (typeof node === \"string\") return createText(node);\n if (!node.tag || (typeof node.tag === 'function')) return createText(JSON.stringify(node));\n isSvg = isSvg || node.tag === \"svg\";\n const element = isSvg\n ? document.createElementNS(\"http://www.w3.org/2000/svg\", node.tag)\n : document.createElement(node.tag);\n\n updateProps(element, node.props, isSvg);\n if (node.children) node.children.forEach(child => element.appendChild(create(child, isSvg)));\n return element\n}\n\nfunction mergeProps(oldProps: {}, newProps: {}): {} {\n newProps['class'] = newProps['class'] || newProps['className'];\n delete newProps['className'];\n const props = {};\n if (oldProps) Object.keys(oldProps).forEach(p => props[p] = null);\n if (newProps) Object.keys(newProps).forEach(p => props[p] = newProps[p]);\n return props;\n}\n\nexport function updateProps(element: Element, props: {}, isSvg) {\n // console.assert(!!element);\n const cached = element[ATTR_PROPS] || {};\n props = mergeProps(cached, props || {});\n element[ATTR_PROPS] = props;\n\n for (const name in props) {\n const value = props[name];\n // if (cached[name] === value) continue;\n // console.log('updateProps', name, value);\n if (name.startsWith('data-')) {\n const dname = name.substring(5);\n const cname = dname.replace(/-(\\w)/g, (match) => match[1].toUpperCase());\n if (element.dataset[cname] !== value) {\n if (value || value === \"\") element.dataset[cname] = value;\n else delete element.dataset[cname];\n }\n } else if (name === 'style') {\n if (element.style.cssText) element.style.cssText = '';\n if (typeof value === 'string') element.style.cssText = value;\n else {\n for (const s in value) {\n if (element.style[s] !== value[s]) element.style[s] = value[s];\n }\n }\n } else if (name.startsWith('xlink')) {\n const xname = name.replace('xlink', '').toLowerCase();\n if (value == null || value === false) {\n element.removeAttributeNS('http://www.w3.org/1999/xlink', xname);\n } else {\n element.setAttributeNS('http://www.w3.org/1999/xlink', xname, value);\n }\n } else if (name.startsWith('on')) {\n if (!value || typeof value === 'function') {\n element[name] = value;\n } else if (typeof value === 'string') {\n if (value) element.setAttribute(name, value);\n else element.removeAttribute(name);\n }\n } else if (/^id$|^class$|^list$|^readonly$|^contenteditable$|^role|-/g.test(name) || isSvg) {\n if (element.getAttribute(name) !== value) {\n if (value) element.setAttribute(name, value);\n else element.removeAttribute(name);\n }\n } else if (element[name] !== value) {\n element[name] = value;\n }\n if (name === 'key' && value) keyCache[value] = element;\n }\n if (props && typeof props['ref'] === 'function') {\n window.requestAnimationFrame(() => props['ref'](element));\n }\n}\n\nfunction render_component(node, parent, idx) {\n const { tag, props, children } = node;\n let key = `_${idx}`;\n let id = props && props['id'];\n if (!id) id = `_${idx}${Date.now()}`;\n else key = id;\n let asTag = 'section';\n if (props && props['as']) {\n asTag = props['as'];\n delete props['as'];\n }\n if (!parent.__componentCache) parent.__componentCache = {};\n let component = parent.__componentCache[key];\n if (!component || !(component instanceof tag) || !component.element) {\n const element = document.createElement(asTag);\n component = parent.__componentCache[key] = new tag({ ...props, children }).start(element);\n }\n if (component.mounted) {\n const new_state = component.mounted(props, children, component.state);\n (typeof new_state !== 'undefined') && component.setState(new_state);\n }\n updateProps(component.element, props, false);\n return component.element;\n}\n\nfunction createComponent(node, parent, idx = 0) {\n if (typeof node === 'string') return node;\n if (Array.isArray(node)) return node.map(child => createComponent(child, parent, idx++));\n let vdom = node;\n if (node && typeof node.tag === 'function' && Object.getPrototypeOf(node.tag).__isAppRunComponent) {\n vdom = render_component(node, parent, idx);\n }\n if (vdom && Array.isArray(vdom.children)) {\n const new_parent = vdom.props?._component;\n if (new_parent) {\n let i = 0;\n vdom.children = vdom.children.map(child => createComponent(child, new_parent, i++));\n } else {\n vdom.children = vdom.children.map(child => createComponent(child, parent, idx++));\n }\n }\n return vdom;\n}\n", "declare var customElements;\n\nexport type CustomElementOptions = {\n render?: boolean;\n shadow?: boolean;\n history?: boolean;\n global_event?: boolean;\n observedAttributes?: string[];\n};\n\nexport const customElement = (componentClass, options: CustomElementOptions = {}) => class CustomElement extends HTMLElement {\n private _shadowRoot;\n private _component;\n private _attrMap: (arg0: string) => string;\n public on;\n public run;\n constructor() {\n super();\n }\n get component() { return this._component; }\n get state() { return this._component.state; }\n\n static get observedAttributes() {\n // attributes need to be set to lowercase in order to get observed\n return (options.observedAttributes || []).map(attr => attr.toLowerCase());\n }\n\n connectedCallback() {\n if (this.isConnected && !this._component) {\n const opts = options || {};\n this._shadowRoot = opts.shadow ? this.attachShadow({ mode: 'open' }) : this;\n const observedAttributes = (opts.observedAttributes || [])\n\n const attrMap = observedAttributes.reduce((map, name) => {\n const lc = name.toLowerCase()\n if (lc !== name) {\n map[lc] = name\n }\n return map\n }, {})\n this._attrMap = (name: string) : string => attrMap[name] || name\n\n const props = {};\n Array.from(this.attributes).forEach(item => props[this._attrMap(item.name)] = item.value);\n\n // add getters/ setters to allow observation on observedAttributes\n observedAttributes.forEach(name => {\n if (this[name] !== undefined) props[name] = this[name];\n Object.defineProperty(this, name, {\n get(): any {\n return props[name];\n },\n set(this: CustomElement, value: unknown) {\n // trigger change event\n this.attributeChangedCallback(name, props[name], value)\n },\n configurable: true,\n enumerable: true\n });\n })\n\n const children = this.children ? Array.from(this.children) : [];\n children.forEach(el => el.parentElement.removeChild(el));\n this._component = new componentClass({ ...props, children }).mount(this._shadowRoot, opts);\n // attach props to component\n this._component._props = props;\n // expose dispatchEvent\n this._component.dispatchEvent = this.dispatchEvent.bind(this)\n if (this._component.mounted) {\n const new_state = this._component.mounted(props, children, this._component.state);\n if (typeof new_state !== 'undefined') this._component.state = new_state;\n }\n this.on = this._component.on.bind(this._component);\n this.run = this._component.run.bind(this._component);\n if (!(opts.render===false)) this._component.run('.');\n }\n }\n\n disconnectedCallback() {\n this._component?.unload?.();\n this._component?.unmount?.();\n this._component = null;\n }\n\n attributeChangedCallback(name: string, oldValue: unknown, value: unknown) {\n if (this._component) {\n // camelCase attributes arrive only in lowercase\n const mappedName = this._attrMap(name);\n // store the new property/ attribute\n this._component._props[mappedName] = value;\n this._component.run('attributeChanged', mappedName, oldValue, value);\n\n if (value !== oldValue && !(options.render === false)) {\n window.requestAnimationFrame(() => {\n // re-render state with new combined props on next animation frame\n this._component.run('.')\n })\n }\n }\n }\n}\n\nexport default (name: string, componentClass, options?: CustomElementOptions) => {\n (typeof customElements !== 'undefined') && customElements.define(name, customElement(componentClass, options))\n}\n", "import webComponent, { CustomElementOptions } from './web-component';\n\n// tslint:disable:no-invalid-this\nexport const Reflect = {\n\n meta: new WeakMap(),\n\n defineMetadata(metadataKey, metadataValue, target) {\n if (!this.meta.has(target)) this.meta.set(target, {});\n this.meta.get(target)[metadataKey] = metadataValue;\n },\n\n getMetadataKeys(target) {\n target = Object.getPrototypeOf(target);\n return this.meta.get(target) ? Object.keys(this.meta.get(target)) : [];\n },\n\n getMetadata(metadataKey, target) {\n target = Object.getPrototypeOf(target);\n return this.meta.get(target) ? this.meta.get(target)[metadataKey] : null;\n }\n}\n\nexport function update(events?: E, options: any = {}) {\n return (target: any, key: string, descriptor: any) => {\n const name = events ? events.toString() : key;\n Reflect.defineMetadata(`apprun-update:${name}`,\n { name, key, options }, target);\n return descriptor;\n }\n}\n\nexport function on(events?: E, options: any = {}) {\n return function (target: any, key: string) {\n const name = events ? events.toString() : key;\n Reflect.defineMetadata(`apprun-update:${name}`,\n { name, key, options }, target)\n }\n}\n\nexport function customElement(name: string, options?: CustomElementOptions) {\n return function _customElement(constructor: T) {\n webComponent(name, constructor, options);\n return constructor;\n }\n}\n\n", "import app from './app';\n\nconst getStateValue = (component, name) => {\n return (name ? component['state'][name] : component['state']) || '';\n}\n\nconst setStateValue = (component, name, value) => {\n if (name) {\n const state = component['state'] || {};\n state[name] = value;\n component.setState(state);\n } else {\n component.setState(value);\n }\n}\n\nexport default (key: string, props: {}, tag, component) => {\n if (key.startsWith('$on')) {\n const event = props[key];\n key = key.substring(1)\n if (typeof event === 'boolean') {\n props[key] = e => component.run(key, e);\n } else if (typeof event === 'string') {\n props[key] = e => component.run(event, e);\n } else if (typeof event === 'function') {\n props[key] = e => component.setState(event(component.state, e));\n } else if (Array.isArray(event)) {\n const [handler, ...p] = event;\n if (typeof handler === 'string') {\n props[key] = e => component.run(handler, ...p, e);\n } else if (typeof handler === 'function') {\n props[key] = e => component.setState(handler(component.state, ...p, e));\n }\n }\n\n } else if (key === '$bind') {\n const type = props['type'] || 'text';\n const name = typeof props[key] === 'string' ? props[key] : props['name'];\n if (tag === 'input') {\n switch (type) {\n case 'checkbox':\n props['checked'] = getStateValue(component, name);\n props['onclick'] = e => setStateValue(component, name || e.target.name, e.target.checked);\n break;\n case 'radio':\n props['checked'] = getStateValue(component, name) === props['value'];\n props['onclick'] = e => setStateValue(component, name || e.target.name, e.target.value);\n break;\n case 'number':\n case 'range':\n props['value'] = getStateValue(component, name);\n props['oninput'] = e => setStateValue(component, name || e.target.name, Number(e.target.value));\n break;\n default:\n props['value'] = getStateValue(component, name);\n props['oninput'] = e => setStateValue(component, name || e.target.name, e.target.value);\n }\n } else if (tag === 'select') {\n props['value'] = getStateValue(component, name);\n props['onchange'] = e => {\n if (!e.target.multiple) { // multiple selection use $bind on option\n setStateValue(component, name || e.target.name, e.target.value);\n }\n }\n } else if (tag === 'option') {\n props['selected'] = getStateValue(component, name);\n props['onclick'] = e => setStateValue(component, name || e.target.name, e.target.selected);\n } else if (tag === 'textarea') {\n props['innerHTML'] = getStateValue(component, name);\n props['oninput'] = e => setStateValue(component, name || e.target.name, e.target.value);\n }\n } else {\n app.run('$', { key, tag, props, component });\n }\n}", "\r\nimport app, { App } from './app';\r\nimport { Reflect } from './decorator'\r\nimport { View, Update, ActionDef, ActionOptions, MountOptions } from './types';\r\nimport directive from './directive';\r\n\r\nconst componentCache = new Map();\r\napp.on('get-components', o => o.components = componentCache);\r\n\r\nconst REFRESH = state => state;\r\n\r\nexport class Component {\r\n static __isAppRunComponent = true;\r\n private _app = new App();\r\n private _actions = [];\r\n private _global_events = [];\r\n private _state;\r\n private _history = [];\r\n private _history_idx = -1;\r\n private enable_history;\r\n private global_event;\r\n public element;\r\n public rendered;\r\n public mounted;\r\n public unload;\r\n private tracking_id;\r\n private observer;\r\n\r\n render(element: HTMLElement, node) {\r\n app.render(element, node, this);\r\n }\r\n\r\n private _view(state) {\r\n if (!this.view) return;\r\n const h = app.createElement;\r\n app.h = app.createElement = (tag, props, ...children) => {\r\n props && Object.keys(props).forEach(key => {\r\n if (key.startsWith('$')) {\r\n directive(key, props, tag, this);\r\n delete props[key];\r\n }\r\n });\r\n return h(tag, props, ...children);\r\n }\r\n const html = this.view(state);\r\n app.h = app.createElement = h;\r\n return html;\r\n }\r\n\r\n private renderState(state: T, vdom = null) {\r\n if (!this.view) return;\r\n let html = vdom || this._view(state);\r\n\r\n app['debug'] && app.run('debug', {\r\n component: this,\r\n _: html ? '.' : '-',\r\n state,\r\n vdom: html,\r\n el: this.element\r\n });\r\n\r\n if (typeof document !== 'object') return;\r\n\r\n const el = (typeof this.element === 'string') ?\r\n document.getElementById(this.element) : this.element;\r\n\r\n if (el) {\r\n const tracking_attr = '_c';\r\n if (!this.unload) {\r\n el.removeAttribute && el.removeAttribute(tracking_attr);\r\n } else if (el['_component'] !== this || el.getAttribute(tracking_attr) !== this.tracking_id) {\r\n this.tracking_id = new Date().valueOf().toString();\r\n el.setAttribute(tracking_attr, this.tracking_id);\r\n if (typeof MutationObserver !== 'undefined') {\r\n if (!this.observer) this.observer = new MutationObserver(changes => {\r\n if (changes[0].oldValue === this.tracking_id || !document.body.contains(el)) {\r\n this.unload(this.state);\r\n this.observer.disconnect();\r\n this.observer = null;\r\n }\r\n });\r\n this.observer.observe(document.body, {\r\n childList: true, subtree: true,\r\n attributes: true, attributeOldValue: true, attributeFilter: [tracking_attr]\r\n });\r\n }\r\n }\r\n el['_component'] = this;\r\n }\r\n if (!vdom) {\r\n this.render(el, html);\r\n }\r\n this.rendered && this.rendered(this.state);\r\n }\r\n\r\n public setState(state: T, options: ActionOptions\r\n = { render: true, history: false }) {\r\n if (state instanceof Promise) {\r\n // Promise will not be saved or rendered\r\n // state will be saved and rendered when promise is resolved\r\n // Wait for previous promise to complete first\r\n Promise.all([state, this._state]).then(v => {\r\n if (v[0]) this.setState(v[0]);\r\n }).catch(err => {\r\n console.error(err);\r\n throw err;\r\n });\r\n this._state = state;\r\n } else {\r\n this._state = state;\r\n if (state == null) return;\r\n this.state = state;\r\n if (options.render !== false) this.renderState(state);\r\n if (options.history !== false && this.enable_history) {\r\n this._history = [...this._history, state];\r\n this._history_idx = this._history.length - 1;\r\n }\r\n if (typeof options.callback === 'function') options.callback(this.state);\r\n }\r\n }\r\n\r\n private _history_prev = () => {\r\n this._history_idx--;\r\n if (this._history_idx >= 0) {\r\n this.setState(this._history[this._history_idx], { render: true, history: false });\r\n }\r\n else {\r\n this._history_idx = 0;\r\n }\r\n };\r\n\r\n private _history_next = () => {\r\n this._history_idx++;\r\n if (this._history_idx < this._history.length) {\r\n this.setState(this._history[this._history_idx], { render: true, history: false });\r\n }\r\n else {\r\n this._history_idx = this._history.length - 1;\r\n }\r\n };\r\n\r\n constructor(\r\n protected state?: T,\r\n protected view?: View,\r\n protected update?: Update,\r\n protected options?) {\r\n }\r\n\r\n start = (element = null, options?: MountOptions): Component => {\r\n return this.mount(element, { ...options, render: true });\r\n }\r\n\r\n public mount(element = null, options?: MountOptions): Component {\r\n console.assert(!this.element, 'Component already mounted.')\r\n this.options = options = { ...this.options, ...options };\r\n this.element = element;\r\n this.global_event = options.global_event;\r\n this.enable_history = !!options.history;\r\n\r\n if (this.enable_history) {\r\n this.on(options.history.prev || 'history-prev', this._history_prev);\r\n this.on(options.history.next || 'history-next', this._history_next);\r\n }\r\n\r\n if (options.route) {\r\n this.update = this.update || {};\r\n this.update[options.route] = REFRESH;\r\n }\r\n\r\n this.add_actions();\r\n this.state = this.state ?? this['model'] ?? {};\r\n if (typeof this.state === 'function') this.state = this.state();\r\n if (options.render) {\r\n this.setState(this.state, { render: true, history: true });\r\n } else {\r\n this.setState(this.state, { render: false, history: true });\r\n }\r\n if (app['debug']) {\r\n if (componentCache.get(element)) { componentCache.get(element).push(this) }\r\n else { componentCache.set(element, [this])}\r\n }\r\n return this;\r\n }\r\n\r\n is_global_event(name: string): boolean {\r\n return name && (\r\n this.global_event ||\r\n this._global_events.indexOf(name) >= 0 ||\r\n name.startsWith('#') || name.startsWith('/') || name.startsWith('@'));\r\n }\r\n\r\n add_action(name: string, action, options: ActionOptions = {}) {\r\n if (!action || typeof action !== 'function') return;\r\n if (options.global) this._global_events.push(name);\r\n this.on(name as any, (...p) => {\r\n\r\n app['debug'] && app.run('debug', {\r\n component: this,\r\n _: '>',\r\n event: name, p,\r\n current_state: this.state,\r\n options\r\n });\r\n\r\n const newState = action(this.state, ...p);\r\n\r\n app['debug'] && app.run('debug', {\r\n component: this,\r\n _: '<',\r\n event: name, p,\r\n newState,\r\n state: this.state,\r\n options\r\n });\r\n\r\n this.setState(newState, options)\r\n }, options);\r\n }\r\n\r\n add_actions() {\r\n const actions = this.update || {};\r\n Reflect.getMetadataKeys(this).forEach(key => {\r\n if (key.startsWith('apprun-update:')) {\r\n const meta = Reflect.getMetadata(key, this)\r\n actions[meta.name] = [this[meta.key].bind(this), meta.options];\r\n }\r\n })\r\n\r\n const all = {};\r\n if (Array.isArray(actions)) {\r\n actions.forEach(act => {\r\n const [name, action, opts] = act as ActionDef;\r\n const names = name.toString();\r\n names.split(',').forEach(n => all[n.trim()] = [action, opts])\r\n })\r\n } else {\r\n Object.keys(actions).forEach(name => {\r\n const action = actions[name];\r\n if (typeof action === 'function' || Array.isArray(action)) {\r\n name.split(',').forEach(n => all[n.trim()] = action)\r\n }\r\n })\r\n }\r\n\r\n if (!all['.']) all['.'] = REFRESH;\r\n Object.keys(all).forEach(name => {\r\n const action = all[name];\r\n if (typeof action === 'function') {\r\n this.add_action(name, action);\r\n } else if (Array.isArray(action)) {\r\n this.add_action(name, action[0], action[1]);\r\n }\r\n });\r\n }\r\n\r\n public run(event: E, ...args) {\r\n const name = event.toString();\r\n return this.is_global_event(name) ?\r\n app.run(name, ...args) :\r\n this._app.run(name, ...args);\r\n }\r\n\r\n public on(event: E, fn: (...args) => void, options?: any) {\r\n const name = event.toString();\r\n this._actions.push({ name, fn });\r\n return this.is_global_event(name) ?\r\n app.on(name, fn, options) :\r\n this._app.on(name, fn, options);\r\n }\r\n\r\n public unmount() {\r\n this.observer?.disconnect();\r\n this._actions.forEach(action => {\r\n const { name, fn } = action;\r\n this.is_global_event(name) ?\r\n app.off(name, fn) :\r\n this._app.off(name, fn);\r\n });\r\n }\r\n}\r\n", "import app from './app';\n\nexport type Route = (url: string, ...args: any[]) => any;\n\nexport const ROUTER_EVENT: string = '//';\nexport const ROUTER_404_EVENT: string = '///';\n\nexport const route: Route = (url: string) => {\n if (!url) url = '#';\n if (url.startsWith('#')) {\n const [name, ...rest] = url.split('/');\n app.run(name, ...rest) || app.run(ROUTER_404_EVENT, name, ...rest);\n app.run(ROUTER_EVENT, name, ...rest);\n } else if (url.startsWith('/')) {\n const [_, name, ...rest] = url.split('/');\n app.run('/' + name, ...rest) || app.run(ROUTER_404_EVENT, '/' + name, ...rest);\n app.run(ROUTER_EVENT, '/' + name, ...rest);\n } else {\n app.run(url) || app.run(ROUTER_404_EVENT, url);\n app.run(ROUTER_EVENT, url);\n }\n}\nexport default route;", "import app from './app';\nimport { createElement, render, Fragment } from './vdom';\nimport { Component } from './component';\nimport { VNode, View, Action, Update, EventOptions, ActionOptions, MountOptions, AppStartOptions } from './types';\nimport { on, update, customElement } from './decorator';\nimport webComponent, { CustomElementOptions } from './web-component';\nimport { Route, route, ROUTER_EVENT, ROUTER_404_EVENT } from './router';\n\nexport interface IApp {\n start(element?: Element | string, model?: T, view?: View, update?: Update,\n options?: AppStartOptions): Component;\n on(name: string, fn: (...args: any[]) => void, options?: any): void;\n off(name: string, fn: (...args: any[]) => void): void;\n run(name: string, ...args: any[]): number;\n h(tag: string | Function, props, ...children): VNode | VNode[];\n createElement(tag: string | Function, props, ...children): VNode | VNode[];\n render(element: HTMLElement, node: VNode): void;\n Fragment(props, ...children): any[];\n route?: Route;\n webComponent(name: string, componentClass, options?: CustomElementOptions): void;\n}\n\napp.h = app.createElement = createElement;\napp.render = render;\napp.Fragment = Fragment;\napp.webComponent = webComponent;\n\napp.start = (element?: Element, model?: T, view?: View, update?: Update,\n options?: AppStartOptions): Component => {\n const opts = { ...options, render: true, global_event: true };\n const component = new Component(model, view, update);\n if (options && options.rendered) component.rendered = options.rendered;\n component.mount(element, opts);\n return component;\n};\n\nconst NOOP = _ => {/* Intentionally empty */ }\napp.on('$', NOOP);\napp.on('debug', _ => NOOP);\napp.on(ROUTER_EVENT, NOOP);\napp.on('#', NOOP);\napp['route'] = route;\napp.on('route', url => app['route'] && app['route'](url));\n\nif (typeof document === 'object') {\n document.addEventListener(\"DOMContentLoaded\", () => {\n if (app['route'] === route) {\n window.onpopstate = () => route(location.hash);\n if (!document.body.hasAttribute('apprun-no-init')) route(location.hash);\n }\n });\n}\n\nexport type StatelessComponent = (args: T) => string | VNode | void;\nexport { app, Component, View, Action, Update, on, update, EventOptions, ActionOptions, MountOptions, Fragment }\nexport { update as event };\nexport { ROUTER_EVENT, ROUTER_404_EVENT };\nexport { customElement, CustomElementOptions, AppStartOptions };\nexport default app as IApp;\n\nif (typeof window === 'object') {\n window['Component'] = Component;\n window['React'] = app;\n window['on'] = on;\n window['customElement'] = customElement;\n}\n\n\n", "import { createElement, updateElement, Fragment } from './vdom-my';\nexport function render(element, html, parent?) {\n updateElement(element, html, parent);\n}\nexport { createElement, Fragment };\n\n\n", "/**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n\nvar chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\nfunction InvalidCharacterError(message) {\n this.message = message;\n}\n\nInvalidCharacterError.prototype = new Error();\nInvalidCharacterError.prototype.name = \"InvalidCharacterError\";\n\nfunction polyfill(input) {\n var str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new InvalidCharacterError(\n \"'atob' failed: The string to be decoded is not correctly encoded.\"\n );\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? bs * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ?\n (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)))) :\n 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n return output;\n}\n\nexport default (typeof window !== \"undefined\" &&\n window.atob &&\n window.atob.bind(window)) ||\npolyfill;", "import atob from \"./atob\";\n\nfunction b64DecodeUnicode(str) {\n return decodeURIComponent(\n atob(str).replace(/(.)/g, function(m, p) {\n var code = p.charCodeAt(0).toString(16).toUpperCase();\n if (code.length < 2) {\n code = \"0\" + code;\n }\n return \"%\" + code;\n })\n );\n}\n\nexport default function(str) {\n var output = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n switch (output.length % 4) {\n case 0:\n break;\n case 2:\n output += \"==\";\n break;\n case 3:\n output += \"=\";\n break;\n default:\n throw \"Illegal base64url string!\";\n }\n\n try {\n return b64DecodeUnicode(output);\n } catch (err) {\n return atob(output);\n }\n}", "\"use strict\";\n\nimport base64_url_decode from \"./base64_url_decode\";\n\nexport function InvalidTokenError(message) {\n this.message = message;\n}\n\nInvalidTokenError.prototype = new Error();\nInvalidTokenError.prototype.name = \"InvalidTokenError\";\n\nexport default function(token, options) {\n if (typeof token !== \"string\") {\n throw new InvalidTokenError(\"Invalid token specified\");\n }\n\n options = options || {};\n var pos = options.header === true ? 0 : 1;\n try {\n return JSON.parse(base64_url_decode(token.split(\".\")[pos]));\n } catch (e) {\n throw new InvalidTokenError(\"Invalid token specified: \" + e.message);\n }\n}", "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport app from 'apprun';\nimport jwt_decode, { JwtPayload } from 'jwt-decode';\n\nconst defaultBasePath = window['defaultBasePath'] || '/api';\n\nlet access_token: string = (window && window.localStorage && window.localStorage.getItem('jwt')) || '';\n// let access_token: string = getCookie('jwt');\nexport function getToken() {\n return access_token;\n}\nexport function setToken(token: string) {\n access_token = token;\n // document.cookie = 'jwt=' + token;\n if (!window.localStorage) {return;}\n if (token) {window.localStorage.setItem('jwt', token);} else {window.localStorage.removeItem('jwt');}\n}\n\nconst NProgress = window['NProgress'];\nasync function fetchAsync(method: 'GET' | 'POST' | 'DELETE' | 'PUT', url: string, body?: any) {\n NProgress?.set(0.4);\n const headers = access_token ? { Authorization: `Bearer ${access_token}` } : {};\n headers['Content-Type'] = 'application/json; charset=utf-8';\n url = `${defaultBasePath}${url}`;\n const response = await window['fetch'](url, {\n method,\n headers,\n body: body && JSON.stringify(body)\n });\n NProgress?.done();\n if (response.status === 401) {\n app.run('show-message', 'Authentication failed ... \uD83D\uDEAB\uD83E\uDD1A\uD83D\uDE26', 401);\n app.run('#login', response);\n return;\n }\n if (!response.ok) {\n app.run('show-message', 'Calling the server ... \uD83D\uDCA5\uD83D\uDC4E\uD83D\uDE13', 500);\n throw response;\n }\n\n return response.json();\n}\n\nasync function fetchFileAsync(method: 'GET' | 'POST' | 'DELETE' | 'PUT', url: string, body?: any) {\n NProgress?.set(0.4);\n const headers = access_token ? { Authorization: `Bearer ${access_token}` } : {};\n headers['enctype'] = 'multipart/form-data';\n url = `${defaultBasePath}${url}`;\n const response = await window['fetch'](url, {\n method,\n headers,\n body: body\n });\n NProgress?.done();\n if (response.status === 401) {\n app.run('show-message', 'Authentication failed ... \uD83D\uDEAB\uD83E\uDD1A\uD83D\uDE26', 401);\n app.run('#login', response);\n return;\n }\n if (!response.ok) {\n throw response.statusText;\n }\n\n return response.text();\n}\n\nasync function check_jwt() {\n try {\n const access_token_expiry = jwt_decode(access_token).exp;\n if (Date.now() / 1000 > access_token_expiry) {\n const newToken = await fetchAsync('GET', '/users/refreshJWT');\n setToken(newToken);\n }\n return true;\n } catch {\n setToken(null);\n }\n}\n\nexport async function get(url: string, auth = true): Promise {\n const ok = !auth || await check_jwt();\n if (ok) {return fetchAsync('GET', url);}\n}\n\nexport async function post(url: string, body: any, auth = true): Promise {\n const ok = !auth || await check_jwt();\n if (ok) {return fetchAsync('POST', url, body);}\n}\n\nexport function postFile(url: string, body?: any): Promise {\n return fetchFileAsync('POST', url, body);\n}\n\nexport function del(url: string, body?: any) {\n return fetchAsync('DELETE', url, body);\n}\n\nexport function put(url: string, body?: any) {\n return fetchAsync('PUT', url, body);\n}\n\nexport function toQueryString(obj) {\n const parts = [];\n for (const i in obj) {\n // eslint-disable-next-line no-prototype-builtins\n if (obj.hasOwnProperty(i)) {\n parts.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));\n }\n }\n return parts.join('&');\n}\n\nexport function serializeObject(form) {\n const obj = {};\n if (typeof form === 'object' && form.nodeName === 'FORM') {\n for (let i = 0; i < form.elements.length; i++) {\n const field = form.elements[i];\n if (\n field.name &&\n field.type !== 'file' &&\n field.type !== 'reset' &&\n field.type !== 'submit' &&\n field.type !== 'button'\n ) {\n if (field.type === 'select-multiple') {\n obj[field.name] = '';\n let tempvalue = '';\n for (let j = 0; j < form.elements[i].options.length; j++) {\n if (field.options[j].selected) {tempvalue += field.options[j].value + ';';}\n }\n if (tempvalue.charAt(tempvalue.length - 1) === ';') {obj[field.name] = tempvalue.substring(0, tempvalue.length - 1);}\n } else if ((field.type !== 'checkbox' && field.type !== 'radio') || field.checked) {\n obj[field.name] = field.value;\n }\n }\n }\n }\n\n return obj as T;\n}\n\nexport function serializeObjectEnhanced(form) {\n const obj = {};\n if (typeof form === 'object' && form.nodeName === 'FORM') {\n for (let i = 0; i < form.elements.length; i++) {\n const field = form.elements[i];\n if (\n field.name &&\n field.type !== 'file' &&\n field.type !== 'reset' &&\n field.type !== 'submit' &&\n field.type !== 'button'\n ) {\n if (field.type === 'select-multiple') {\n obj[field.name] = '';\n let tempvalue = '';\n for (let j = 0; j < form.elements[i].options.length; j++) {\n if (field.options[j].selected) {tempvalue += field.options[j].value + ';';}\n }\n if (tempvalue.charAt(tempvalue.length - 1) === ';') {obj[field.name] = tempvalue.substring(0, tempvalue.length - 1);}\n } else if ((field.type !== 'checkbox' && field.type !== 'radio') || field.checked) {\n obj[field.name] = field.value;\n } else if ((field.type === 'checkbox' || field.type === 'radio') && !field.checked) {\n obj[field.name] = '';\n }\n }\n }\n }\n return obj as T;\n}\n", "import {\r\n getToken,\r\n setToken,\r\n toQueryString,\r\n serializeObject,\r\n get,\r\n post,\r\n postFile,\r\n serializeObjectEnhanced,\r\n} from './fetch';\r\n\r\nimport jwt_decode from 'jwt-decode';\r\n\r\nexport { toQueryString, serializeObject, serializeObjectEnhanced };\r\n\r\nexport interface IProfile {\r\n email: string;\r\n token: string;\r\n}\r\nexport interface ISession {\r\n user: IProfile;\r\n access?: IAccessToken;\r\n}\r\n\r\nexport interface IAccessToken {\r\n aud: string;\r\n exp: number;\r\n firstname: string;\r\n iat: number;\r\n iss: string;\r\n lang: string;\r\n lastname: string;\r\n nbf: number;\r\n roles: string;\r\n sub: string;\r\n role: string[];\r\n userID: string;\r\n unique_name: string;\r\n}\r\nlet accessMap;\r\n\r\nexport const rpt = {\r\n getRpts: (lang) => {\r\n return get('/excelRpt/getRpts/' + lang);\r\n },\r\n getLocs: () => {\r\n return get('/excelRpt/userlocations/en');\r\n },\r\n getToken: () => getToken(),\r\n getRptUrl: () => {\r\n return 'https://rlp-frs-qa.rlpnetwork.com/api/excelexports/12391/2024-06-01/2024-06-30/2/en/' + '?t=' + getToken();\r\n }\r\n};\r\n\r\n// Type definitions for Google Sign-In API\r\ndeclare global {\r\n interface Window {\r\n google?: {\r\n accounts: {\r\n oauth2: {\r\n initTokenClient(config: {\r\n client_id: string;\r\n scope: string;\r\n callback: (response: {\r\n error?: string;\r\n credential?: string;\r\n access_token?: string;\r\n expires_in?: number;\r\n scope?: string;\r\n token_type?: string;\r\n }) => void;\r\n }): {\r\n requestAccessToken(): void;\r\n };\r\n };\r\n };\r\n };\r\n }\r\n}\r\n\r\n// Load Google Sign-In API\r\nconst loadGoogleSignIn = (): Promise => {\r\n return new Promise((resolve) => {\r\n const script = document.createElement('script');\r\n script.src = 'https://accounts.google.com/gsi/client';\r\n script.async = true;\r\n script.defer = true;\r\n script.onload = () => resolve();\r\n document.head.appendChild(script);\r\n });\r\n};\r\n\r\nexport const auth = {\r\n token: (): string => getToken(),\r\n current: (): IAccessToken => {\r\n let jwt;\r\n const token = getToken();\r\n try {\r\n jwt = token ? jwt_decode(token) : null;\r\n } catch (err) {\r\n // eslint-disable-next-line no-console\r\n console.error(err);\r\n }\r\n return jwt;\r\n },\r\n signIn: async (user: { email: string; password: string }) => {\r\n const session = await post('/users/login', { user }, false);\r\n setToken(session.user.token);\r\n try {\r\n const jwt = getToken() ? jwt_decode(getToken()) : null;\r\n //console.log(jwt);\r\n const roles = jwt.role;\r\n if (roles.includes('rlp_IngestSSO')) {\r\n const result = await get('/sso/jwt/' + 'IRE' + '/' + 'en');\r\n setToken(null);\r\n document.cookie = 'jwt=; expires=Thu, 01 Jan 1970 00:00:01 GMT';\r\n window.location.replace(result);\r\n return 'stop';\r\n }\r\n } catch (err) {\r\n // eslint-disable-next-line no-console\r\n console.error(err);\r\n }\r\n accessMap = await get('/users/access');\r\n return session;\r\n },\r\n signOut: () => {\r\n setToken(null);\r\n },\r\n hasPermission: async (name: string, permission: string) => {\r\n if (!accessMap) {\r\n accessMap = await get('/users/access');\r\n }\r\n const accessRow = accessMap?.find(p => p.obj === name);\r\n return accessRow && accessRow.acc.includes(permission);\r\n },\r\n getCrmAuthParam: () => {\r\n return get('/sso/getauthparam/crm/');\r\n },\r\n signInWithGoogle: async () => {\r\n try {\r\n // Load Google Sign-In API if not already loaded\r\n if (!window.google) {\r\n await loadGoogleSignIn();\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const client = window.google.accounts.oauth2.initTokenClient({\r\n client_id: '436712924596-5eur9m3ptir4o1c05avoi9bsuce1h6fv.apps.googleusercontent.com', // This should be configured in the application\r\n scope: 'email profile',\r\n callback: async (response) => {\r\n if (response.error) {\r\n reject(new Error(response.error));\r\n return;\r\n }\r\n\r\n try {\r\n const session = await post('/users/google-signin', {\r\n AccessToken: response.access_token\r\n }, false);\r\n\r\n setToken(session.user.token);\r\n\r\n const jwt = getToken() ? jwt_decode(getToken()) : null;\r\n if (jwt?.role.includes('rlp_IngestSSO')) {\r\n const result = await get('/sso/jwt/' + 'IRE' + '/' + 'en');\r\n setToken(null);\r\n document.cookie = 'jwt=; expires=Thu, 01 Jan 1970 00:00:01 GMT';\r\n window.location.replace(result);\r\n resolve('stop');\r\n return;\r\n }\r\n accessMap = await get('/users/access');\r\n\r\n resolve(session);\r\n } catch (error) {\r\n // eslint-disable-next-line no-console\r\n console.error('Google sign-in failed:', error);\r\n reject(error); // This will be handled by the UI layer without refreshing\r\n }\r\n\r\n }\r\n });\r\n\r\n client.requestAccessToken();\r\n });\r\n } catch (error) {\r\n throw new Error('Failed to initialize Google Sign In');\r\n }\r\n }\r\n};\r\n\r\nexport const users = {\r\n search: (request, lang = 0) => {\r\n return post('/users/search/' + lang.toString(), request);\r\n },\r\n searchAdvance: (request) => {\r\n return post('/users/searchadvance', request);\r\n },\r\n Post: (request) => {\r\n return post('/users/', request);\r\n },\r\n checkEmailAvailability: (email) => {\r\n return get('/users/checkEmailAvailability/' + email + '/');\r\n },\r\n QuickLinks: (payload) => {\r\n return post('/users/addQuickLinks/', payload);\r\n },\r\n GetQuickLinks: (userEmail) => {\r\n return post('/users/getQuickLinks/', userEmail);\r\n },\r\n GetRoyalMag: (userEmail) => {\r\n return post('/users/getRoyalMag/', userEmail);\r\n },\r\n GetCompanyPersonId: (userId) => {\r\n return post('/users/getCompanyPersonId/', userId);\r\n },\r\n DeleteQuickLinks: (payload) => {\r\n return post('/users/deleteQuickLinks/', payload);\r\n },\r\n getUser: (email, personID) => {\r\n return get('/users/profile/' + email + '/' + personID);\r\n },\r\n getUserPropertyBag: (uname) => {\r\n return get('/users/properties/' + uname + '/');\r\n },\r\n getUserPhoto: (uname) => {\r\n return get('/users/photo/' + uname + '/');\r\n },\r\n resetProfilePassword: (payload) => {\r\n return post('/users/resetProfilePassword/', payload);\r\n },\r\n upsertUserProperty: (uname, model) => {\r\n return post('/users/properties/' + uname + '/', model);\r\n },\r\n deleteUserProperty: (uname, model) => {\r\n return post('/users/properties/del/' + uname + '/', model);\r\n },\r\n getAwardsTracking: (email) => {\r\n return post('/awardstracking/', email);\r\n },\r\n saveProfile: (model) => {\r\n return post('/users/saveProfile', model);\r\n },\r\n postUserAreas: (personId, model) => {\r\n return post('/users/' + personId + '/areaserviced', model);\r\n },\r\n postExpertTopic: (personId, model) => {\r\n return post('/users/' + personId + '/experttopic', model);\r\n },\r\n getUserLocations: (email) => {\r\n return get('/users/locations/' + email + '/');\r\n },\r\n getUsersList: (companyId, locationId, filter = '') => {\r\n return get('/users/' + (companyId ? companyId : 0) + '/' + (locationId ? locationId : 0) + '/' + filter);\r\n },\r\n getTerminateProfile: (email) => {\r\n return get('/users/terminateprofile/' + email + '/');\r\n },\r\n getPotentialTransferees: (email, terminateuseremail) => {\r\n return get('/users/potentialtransferees/' + email + '/' + terminateuseremail + '/');\r\n },\r\n terminateUser: (model) => {\r\n return post('/users/terminateUser', model);\r\n },\r\n getOneTimePwd: (id) => {\r\n return get('/users/impersonation/' + id + '/');\r\n },\r\n initiateForceSync: (id) => {\r\n return get('/users/forcesync/' + id + '/');\r\n },\r\n getUserCompany: (email) => {\r\n return get('/users/company/' + email + '/');\r\n },\r\n getUserSearchLocations: (email) => {\r\n return get('/users/searchlocations/' + email + '/');\r\n },\r\n isCustomerCare: (email) => {\r\n return get('/users/isCustomerCare/' + email + '/');\r\n },\r\n isManageUser: (email) => {\r\n return get('/users/isManageUser/' + email + '/');\r\n },\r\n getRecoveryEmail: (email) => {\r\n return get('/users/recoveryEmail/' + email + '/', false);\r\n },\r\n sendForgotPasswordInstructions: (email) => {\r\n return get('/users/sendForgotPasswordInstructions/' + email + '/', false);\r\n },\r\n resetPassword: (model) => {\r\n return post('/users/resetPassword', model, false);\r\n },\r\n getReactivateProfile: (email) => {\r\n return get('/users/reactivateprofile/' + email + '/');\r\n },\r\n reactivateUser: (model) => {\r\n return post('/users/reactivateUser', model);\r\n },\r\n setPassword: (personId, password) => {\r\n return post('/users/' + personId + '/' + 'setpassword', password);\r\n },\r\n getDomain: (model) => {\r\n return post('/users/getDomain', model);\r\n },\r\n saveExpertData: (model) => {\r\n return post('/users/saveExpertData', model);\r\n },\r\n getExpertData: (email) => {\r\n return get('/users/getExpertData/' + email + '/');\r\n },\r\n parkEmail: (id, park) => {\r\n return post('/users/parkemail/' + id + '/', park);\r\n },\r\n saveExpertNewEvent: (model) => {\r\n return post('/users/saveExpertNewEvent', model);\r\n },\r\n updateExpertEvents: (model) => {\r\n return post('/users/updateExpertEvents', model);\r\n },\r\n deleteExpertEvent: (model) => {\r\n return post('/users/deleteExpertEvent', model);\r\n },\r\n getCalendarInfo: (email) => {\r\n return get('/users/brokersharedcalendars/' + email + '/');\r\n },\r\n getPersonID: (email) => {\r\n return get('/users/personid/' + email + '/');\r\n },\r\n getGoogleDeleteList: () => {\r\n return get('/users/googledeleteforapproval/');\r\n },\r\n approveGoogleDelete: (model) => {\r\n return post('/users/approvegoogledelete', model);\r\n },\r\n getMenus: () => {\r\n return get('/WPObjAccess/GetMenuIdList');\r\n },\r\n getHeader: () => {\r\n return get('/users/getheader');\r\n },\r\n getTeams: (email, langCt) => {\r\n return get('/users/getteams/' + email + '/' + langCt);\r\n },\r\n getIreDashboardData: (personId) => {\r\n return get('/users/getIreDashboardData/' + personId);\r\n },\r\n getOldEmployeeDateHistory: (personId) => {\r\n return get('/users/getOldEmployeeDateHistory/' + personId);\r\n },\r\n getAuditEmployeeType: (personId) => {\r\n return get('/users/getAuditEmployeeType/' + personId);\r\n },\r\n getAuditLocation: (personId) => {\r\n return get('/users/getAuditLocation/' + personId);\r\n },\r\n getAuditPublicSiteInd: (personId) => {\r\n return get('/users/getAuditPublicSiteInd/' + personId);\r\n },\r\n getAuditPersonAwardPublicInd: (personId, awardId, year) => {\r\n return get('/users/getAuditPersonAwardPublicInd/' + personId + '/' + awardId + '/' + year);\r\n },\r\n getAuditTeamMember: (personId) => {\r\n return get('/users/getAuditTeamMember/' + personId);\r\n },\r\n getAuditNetworkMovement: (personId) => {\r\n return get('/users/getAuditNetworkMovement/' + personId);\r\n }\r\n};\r\n\r\nexport const teams = {\r\n getTeamConstraints: (companyPersonID) => {\r\n return get('/team/getTeamConstraints/' + companyPersonID + '/');\r\n },\r\n updateTeamDate: (dateType, companyPersonID, teamMemberID, request) => {\r\n return post('/team/' + companyPersonID + '/updateTeamMembership/' + teamMemberID + '/' + dateType + '/', request);\r\n },\r\n getTeams: (companyId) => {\r\n return get('/team/' + (companyId ? companyId : ''));\r\n }\r\n};\r\n\r\nexport const companies = {\r\n getAllCompanies: () => {\r\n return get('/Companies');\r\n },\r\n getAllTransferCompanies: () => {\r\n return get('/TransferCompanies');\r\n },\r\n getOpenCompanies: () => {\r\n return get('/OpenCompanies');\r\n },\r\n getCompanyDetail: (request) => {\r\n return get('/Companies/' + request);\r\n },\r\n post: (companyId, model) => {\r\n return post('/Companies/' + companyId, model);\r\n },\r\n getCompanyAddress: (request) => {\r\n return get('/Companies/' + request + '/address');\r\n },\r\n postCompanyAddress: (companyId, model) => {\r\n return post('/Companies/' + companyId + '/address', model);\r\n },\r\n getCompanyPhones: (request) => {\r\n return get('/Companies/' + request + '/phone');\r\n },\r\n postCompanyPhones: (companyId, model) => {\r\n return post('/Companies/' + companyId + '/phone', model);\r\n },\r\n getCompanyLocations: (request) => {\r\n return get('/Companies/' + request + '/locations');\r\n },\r\n getCompaniesByProvince: (provStateCt) => {\r\n return get('/Companies/Prov/' + provStateCt + '/');\r\n },\r\n getAllActiveNonAgents: (request) => {\r\n return get('/Companies/' + request + '/getallactivenonagents');\r\n },\r\n upsertProperty: (id, model) => {\r\n return post('/companies/properties/' + id + '/', model);\r\n },\r\n deleteProperty: (id, model) => {\r\n return post('/companies/properties/del/' + id + '/', model);\r\n },\r\n getRpt: (id, invoiceMonth) => {\r\n window.location.href = window['defaultBasePath'] + ('/companies/report/' + id + '/' + invoiceMonth + '?t=' + getToken());\r\n },\r\n getRptAvailableMonths: (id) => {\r\n return get('/Companies/reportmonths/' + id);\r\n },\r\n initiateForceSync: (id) => {\r\n return get('/companies/forcesync/' + id + '/');\r\n }\r\n};\r\n\r\nexport const locations = {\r\n getAllLocations: () => {\r\n return get('/locations');\r\n },\r\n getLocationDetail: (request) => {\r\n return get('/locations/' + request);\r\n },\r\n getLocationPhones: (request) => {\r\n return get('/locations/' + request + '/phone');\r\n },\r\n getLocationsByCompanyID: (request) => {\r\n return get('/Companies/' + request + '/locations');\r\n },\r\n post: (locationId, model) => {\r\n return post('/locations/' + locationId, model);\r\n },\r\n getLocationAddress: (request) => {\r\n return get('/locations/' + request + '/address');\r\n },\r\n postLocationAddress: (locationId, model) => {\r\n return post('/locations/' + locationId + '/address', model);\r\n },\r\n postLocationAreas: (locationId, model) => {\r\n return post('/locations/' + locationId + '/areaserviced', model);\r\n },\r\n getProperties: (id) => {\r\n return get('/locations/properties/' + id + '/');\r\n },\r\n upsertProperty: (id, model) => {\r\n return post('/locations/properties/' + id + '/', model);\r\n },\r\n deleteProperty: (id, model) => {\r\n return post('/location/properties/del/' + id + '/', model);\r\n },\r\n getCompanyLocationsByUser: (id) => {\r\n return get('/locations/awardLocations/' + id + '/');\r\n },\r\n getAwardbyLocation: (companyId, locationId) => {\r\n return get('/locations/award/' + companyId + '/' + locationId + '/');\r\n },\r\n uploadAwards: (id: number, transferobj: Record) => post('/locations/uploadAward/' + id + '/', transferobj),\r\n updateEligible: (model: Record) => {\r\n return post('/locations/eligible/', model);\r\n },\r\n uploadAwardFile: async (companyId: number, locationId: number, formData: FormData): Promise => {\r\n const res = await postFile(`/locations/uploadAwardFile/${companyId}//${locationId}/`, formData);\r\n return res;\r\n },\r\n confirmAward: (model: Record) => {\r\n return post('/locations/confirmAward/', model);\r\n }\r\n};\r\n\r\nexport const phones = {\r\n getPhones: (objType, objId) => {\r\n return get('/phones/' + objType + '/' + objId);\r\n },\r\n postPhones: (objType, objId, model) => {\r\n return post('/phones/' + objType + '/' + objId, model);\r\n }\r\n};\r\n\r\nexport const addresses = {\r\n getAddress: (objType, objId) => {\r\n return get('/address/' + objType + '/' + objId);\r\n },\r\n postAddress: (objType, objId, model) => {\r\n return post('/address/' + objType + '/' + objId, model);\r\n }\r\n};\r\n\r\nexport const regions = {\r\n getAllRegions: () => {\r\n return get('/regionsserviced');\r\n },\r\n getRegions: (query, province) => {\r\n return get('/regionsserviced?query=' + query + '&province=' + province);\r\n }\r\n};\r\n\r\nexport const commProg = {\r\n get: (personId) => {\r\n return get('/commprog/' + personId);\r\n },\r\n getExHistory: (personId) => {\r\n return get('/commprog/commfeeex/' + personId);\r\n },\r\n getCommFee: () => {\r\n return get('/commprog/commfee/');\r\n },\r\n upsertCommProg: (personId, model) => {\r\n return post('/commprog/' + personId, model);\r\n },\r\n upsertCommFeeEx: (personId, model) => {\r\n return post('/commprog/commfeeex/' + personId, model);\r\n },\r\n getCommConstraints: (companyPersonId) => {\r\n return get('/commprog/commconstraints/' + companyPersonId);\r\n }\r\n};\r\n\r\nexport const ProtectionRoyale = {\r\n get: (personId) => {\r\n return get('/protectionroyale/' + personId);\r\n },\r\n upsertPRSubs: (personId, model) => {\r\n return post('/protectionroyale/' + personId, model);\r\n }\r\n};\r\n\r\nexport const smartLead = {\r\n get: (companyId) => {\r\n return get('/companies/smartlead/' + companyId);\r\n },\r\n getSmartLeadFee: () => {\r\n return get('/companies/smartlead/commfee/');\r\n },\r\n upsertSmartLead: (model) => {\r\n return post('/companies/smartlead/', model);\r\n }\r\n};\r\n\r\nexport const contractOption = {\r\n get: (locationId) => {\r\n return get('/contractoption/' + locationId);\r\n },\r\n upsertContractOption: (locationId, model) => {\r\n return post('/contractoption/' + locationId, model);\r\n },\r\n deleteContractOption: (locationId, model) => {\r\n return post('/deletecontractoption/' + locationId, model);\r\n }\r\n};\r\n\r\nexport const feeException = {\r\n get: (personId) => {\r\n return get('/users/feeexception/' + personId);\r\n },\r\n upsertFeeException: (personId, model) => {\r\n return post('/users/feeexception/' + personId, model);\r\n },\r\n deleteFeeException: (personId, model) => {\r\n return post('/users/deletefeeexception/' + personId, model);\r\n }\r\n};\r\n\r\nexport const obApi = {\r\n getOnboardingTypeOptions: () => {\r\n return get('/onboarding/getOnboardingTypeOptions');\r\n },\r\n transferAgents: (model) => {\r\n return post('/onboarding/rlp2rlp/transfer', model);\r\n }\r\n};\r\n\r\nexport const powerBI = {\r\n getConfig: (name) => {\r\n return get('/powerbi/config/' + name);\r\n }\r\n};\r\n\r\nexport const siteSearch = {\r\n simple: (query, lang = '') => {\r\n return get('/sitesearch/simplesearch?query=' + query.trim() + '&lang=' + lang.trim());\r\n }\r\n};\r\n\r\nexport const referralSearch = {\r\n search: async (searchTerm) => {\r\n return get('/referralsearch?searchTerm=' + searchTerm);\r\n },\r\n searchByType: async (searchTerm, type, id, langCt) => {\r\n const res = await get('/referralsearch?type=' + type + '&searchTerm=' + searchTerm + '&id=' + id + '&langCt=' + langCt);\r\n return res;\r\n },\r\n getPersonDetails: async (companyPersonID, langCt) => {\r\n const res = await get('/rfpersondetails/' + companyPersonID + '/' + langCt);\r\n return res;\r\n },\r\n getExpertDirectoryDetails: async (companyPersonID) => {\r\n const res = await get('/edpersondetails/' + companyPersonID);\r\n return res;\r\n }\r\n};\r\n\r\nexport const expertsDirectorty = {\r\n getExpertsdirectory: async (lang) => {\r\n return get('/getExpertsdirectory/' + lang);\r\n }\r\n};\r\n\r\nexport const Lookup = {\r\n getLookup: async () => {\r\n const response = await window['fetch']('/lookupAuto.json');\r\n const baseLookup = await response.json();\r\n const lkupAddData = await get('/regionsserviced/AdditionalLookupData');\r\n for (const lang of Object.keys(lkupAddData || {})) {\r\n const keys = Object.keys(lkupAddData[lang]);\r\n for (const key of keys) {\r\n const supplyObj = lkupAddData[lang][key];\r\n const lookupObj = baseLookup[lang][key];\r\n baseLookup[lang][key] = lookupObj.concat(supplyObj);\r\n }\r\n }\r\n return baseLookup;\r\n }\r\n};\r\n\r\nexport const api = {\r\n invoke: (method, url, data) => {\r\n if (method === 'POST') {\r\n return post('/' + url, data);\r\n } else {\r\n return get('/' + url);\r\n }\r\n }\r\n};\r\n\r\nexport async function doSSO(partnerId, partnerUrl, lang) {\r\n switch (partnerId) {\r\n case 'TF':\r\n case 'LA':\r\n case 'LL':\r\n case 'IRE': {\r\n const result = await get('/sso/jwt/' + partnerId + '/' + lang);\r\n const url = partnerUrl === 'GetFromWebConfig' ? result : partnerUrl + '?token=' + result;\r\n window.open(url, '_blank');\r\n break;\r\n }\r\n case 'ADWERX':\r\n case 'RM': {\r\n window.open('/api/sso/' + partnerId + '/' + lang + ((partnerUrl) ? '?targetURL=' + partnerUrl : ''));\r\n break;\r\n }\r\n case 'IREPOST': {\r\n const result2 = await get('/sso/jwt/' + 'IRE' + '/' + lang);\r\n const jwt = document.createElement('input');\r\n jwt.value = result2.substring(result2.indexOf('?token=') + 7);\r\n jwt.name = 'jwt';\r\n const form = document.createElement('form');\r\n form.appendChild(jwt);\r\n form.method = 'POST';\r\n form.action = result2.substring(0, result2.indexOf('?token='));\r\n form.target = '_Blank';\r\n document.body.appendChild(form);\r\n form.submit();\r\n break;\r\n }\r\n case 'JUMP':\r\n case 'CARRIAGETRADE':\r\n case 'JUMPREPORTS':\r\n case 'JUMPLE':\r\n case 'SMARTSTUDIO':\r\n case 'JUMPQR':\r\n case 'CLIENTCLICK':\r\n case 'CLIENTCLICKDOMAINS':\r\n case 'JUMPCREATECOMMERCIAL':\r\n case 'JUMPCREATEINVESTMENT':\r\n case 'JUMPCREATEVACANT':\r\n case 'JUMPCREATEFARM':\r\n case 'COMMERCIALPROPERTIESWANTED':\r\n case 'PR':\r\n window.open(`${window['defaultBasePath']}/sso/xml/${partnerId}/${lang}?t=${getToken()}`, '_Blank');\r\n break;\r\n case 'JLR': {\r\n const jlrLang = lang === '1' ? 'fr' : 'en';\r\n window.open(`${window['defaultBasePath']}/sso/${partnerId}/${jlrLang}?t=${getToken()}`, '_Blank');\r\n break;\r\n }\r\n }\r\n}\r\n", "export default {\n 'en': {\n 'PROFILE_LINK': '/manage-profile/#/my_profile',\n 'HELP_CONTENT': 'If you have an active Royal LePage email account, your username is your address, i.e.\u00A0xxxxx@royallepage.ca. If you do not have a Royal LePage email address, please contact your office or Customer Care to confirm your username. If you have any questions or need help, contact us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545.',\n 'AWARD_INFO': '

The award tracker information displayed is based on gross, closed and collected income for the current sales award year (November 16 to November 15).

The commission income displayed is not based on pending trades but on closed and collected trades, and is current as of your brokerage\\'s last financial upload to Royal LePage.

Team size is determined by averaging the daily size of the team member count over the course of the sales award year. If a team size flunctuates over the course of the sales awards year, their qualifying thresholds may also change as a result. Full award qualifying thresholds can be found here.

This awards tracker takes into account the 2% variance for GCI permitted by Royal LePage.

Visit this page for information on the Royal LePage Awards and Recognition Program, and Team Guidelines.

'\n },\n 'fr': {\n 'Welcome %': 'BIENVENUE %',\n 'Login': 'Connexion',\n 'Forgot Password': 'Mot de passe oubli\u00E9',\n 'Fran\u00E7ais': 'English',\n 'Help': 'Aide',\n 'WELCOME': 'BIENVENUE',\n 'Email Address': 'Adresse e-mail',\n 'User Name': 'Nom d\\'utilisateur',\n 'LOG IN TO': 'SE CONNECTER AU',\n 'rlpNetwork': 'R\u00E9seaurlp',\n 'Password': 'Mot de passe',\n 'Login failed': '\u00C9chec de la connexion ',\n 'Invalid username or password': 'Nom d\\'utilisateur ou mot de passe invalide',\n 'The following errors have occurred': 'Les erreurs suivantes ont eu lieu',\n 'Director\\'s Platinum Award': 'Attestation Platine De Directeur',\n 'Diamond Award': 'Attestation Diamant',\n 'Red Diamond Award': 'Prix Diamant rouge',\n 'President\\'s Gold Award': 'Palme D\\'Or Du Pr\u00E9sident',\n 'Master Sales Award': 'Ma\u00EEtre Vendeur',\n 'Sales Achievement Award': 'Vendeur \u00C9m\u00E9rite',\n 'S.A.': 'VE',\n 'M.S.': 'MV',\n 'P.G': 'PO',\n 'D.P': 'PP',\n 'D.A.': 'PD',\n 'R.D.': 'DR',\n 'Work Faster.Work Smarter.rlpNetwork.': 'Travaillez plus rapidement. Travaillez mieux. R\u00E9seaurlp.',\n 'System Status': 'Voir l\\'\u00E9tat des syst\u00E8mes',\n 'Welcome': 'BIENVENUE',\n 'LANGUAGES': 'LANGUES',\n 'PROVINCE': 'PROVINCE',\n 'CITY': 'VILLE',\n 'SPECIALTIES': 'SPECIALITES',\n 'DESIGNATIONS': 'D\u00C9SIGNATIONS',\n 'First Name': 'Pr\u00E9nom',\n 'FirstName': 'Pr\u00E9nom',\n 'DELETE': 'SUPPRIMER',\n 'Page Loading': 'Chargement de la page',\n 'Sign out': 'D\u00E9connexion',\n 'About Us': '\u00C0 propos de nous',\n 'Public Relations': 'Relations publiques',\n 'Contact Information': 'Informations de contact',\n 'Legal': 'L\u00E9gal',\n 'Privacy Policy': 'Politique de la vie priv\u00E9e',\n 'Legal & Business': 'Avis juridique',\n 'Terms of Use': 'Conditions d\\'utilisation',\n 'User Guides': 'Guides d\\'utilisation',\n 'Feedback': 'Commentaires',\n 'Customer Care': 'Assistance \u00E0 la client\u00E8le',\n 'Profile': 'Profil',\n 'Sign Out': 'D\u00E9connexion',\n 'This email will receive Royal LePage communications': 'Cet courriel recevra les communications de Royal LePage',\n 'Profile Preview': 'Aper\u00E7u du Profil',\n 'Manage Users': 'Gestion d\\'utilisateur',\n 'New User': 'Nouvel Utilisateur',\n 'Username': 'Nom d\\'utilisateur',\n 'Last Name': 'Nom de famille',\n 'LastName': 'Nom de famille',\n 'Brokerage': 'Courtage',\n 'Office': 'Bureau',\n 'Status': 'Statut',\n 'Active': 'Actif',\n 'Inactive': 'Inactif',\n 'Advanced Search': 'Recherche Avanc\u00E9e',\n 'Clear Search': 'Effacer la recherche',\n 'Search': 'Recherche',\n 'Name': 'Nom',\n 'Primary Location': 'Bureau principal',\n 'Permission Level': 'Niveau de permission',\n 'Last Logged In': 'Derni\u00E8re connexion',\n 'Current Status': 'Statut actuelle',\n 'Manage Status': 'G\u00E9rer l\\'\u00E9tat',\n 'Your search did not return any results. Please refine your search term(s).': 'Votre recherche n\\'a retourn\u00E9 aucun r\u00E9sultat. S\\'il vous pla\u00EEt affiner votre recherche.',\n 'Referral Directory': 'R\u00E9pertoire de r\u00E9f\u00E9rencement',\n 'Search by city or agent': 'Recherche par ville ou courtier',\n 'Filter By\u2026': 'Filtrer par\u2026',\n 'Networking': 'R\u00E9seau',\n 'Professional Experience': 'Exp\u00E9rience professionnelle',\n 'Professional Experience English': 'Exp\u00E9rience professionnelle anglais',\n 'Professional Experience French': 'Exp\u00E9rience professionnelle fran\u00E7ais',\n 'Internal Remarks': 'Remarques internes',\n 'Awards': 'Distinctions',\n 'Skills and Abilities': 'Comp\u00E9tences',\n 'Professional Designations': 'D\u00E9signations professionnelles',\n 'View ad': 'Voir l\\'annonce',\n 'Please ensure that you click \\'Save\\' after your photo has been uploaded. If you do not click Save, your photo will not display on www.royallepage.ca.': 'Veuillez cliquer \"Enregistrer\" apr\u00E8s avoir t\u00E9l\u00E9harg\u00E9 votre photo. Si vous ne cliquez pas sur Enregistrer, votre photo ne s\\'affichera pas \u00E0 www.royallepage.ca',\n 'Update Photo': 'Mise \u00E0 jour de photos',\n 'Reset Password': 'R\u00E9initialiser le mot de passe',\n 'Cancel': 'Annuler',\n 'Edit Profile': 'Profil',\n 'Speaker/Trainer': 'Conf\u00E9rencier / Formateur',\n 'Hold down the key to select multiple items.': 'Appuyez pour selectionner plusieurs \u00E9l\u00E9ments',\n '* Indicates a required field': '* Indique un champ obligatoire',\n 'Save Changes': 'Enregistrer',\n 'Basic Information': 'Information de base',\n 'CONTACT INFORMATION': 'Informations de contact',\n 'MARKETING': 'MARKETING',\n 'SKILLS': 'Aptitudes et comp\u00E9tences',\n 'BIO': 'BIO',\n 'Invalid Current Password, The password must have at least 8 characters and it should not exceed 40 characters. The Password can contain only alpha-numeric characters': 'Mot de passe actuel invalide, Le mot de passe doit comporter au moins 8 caract\u00E8res et ne doit pas d\u00E9passer 40 caract\u00E8res.Mot de passe peut contenir que des caract\u00E8res alphanum\u00E9riques',\n 'Invalid New Password, The password must have at least 8 characters and it should not exceed 40 characters. The Password can contain only alpha-numeric characters': 'Nouveau mot de passe invalide, Le mot de passe doit comporter au moins 8 caract\u00E8res et ne doit pas d\u00E9passer 40 caract\u00E8res.Mot de passe peut contenir que des caract\u00E8res alphanum\u00E9riques',\n 'Quick LINKS': 'Liens Rapides',\n 'Add': 'Ajouter',\n 'Add/Remove Links': 'Ajouter / Supprimer Liens rapides',\n 'Link Title': 'Lien rapide Nom',\n 'Link URL': 'Lien rapide URL',\n 'Save': 'Enregistrer',\n 'Link Title cannot be empty or less than five characters or greater than 50 characters.': 'Le titre du lien ne peut pas \u00EAtre vide. Le titre du lien doit comporter entre 5 et 50 caract\u00E8res.',\n 'Invalid Link URL': 'URL de lien non valide',\n 'Name on Tag': 'Nom \u00E0 afficher',\n 'Previous affiliation details': 'D\u00E9tails de l\\'affiliation pr\u00E9c\u00E9dente',\n 'Manage Users - New User': 'Gestion d\\'utilisateur - Nouvel utilisateur',\n 'Personnel Type': 'Type de personnel',\n 'Last name': 'Nom de famile',\n 'Select User Name / Email': 'S\u00E9lectionnez Nom d\\'utilisateur / Email',\n 'Check Availability Now': 'V\u00E9rifier la disponibilit\u00E9 en ce moment',\n 'Select Password': 'S\u00E9lectionnnez Mot de passe',\n 'Primary Language': 'Langue principale',\n 'Recruitment Source': 'Source de recrutement',\n 'RecruitmentSource': 'Source de recrutement',\n 'Previous Affiliation': 'Pr\u00E9c\u00E9dente affiliation',\n 'PreviousAffiliation': 'Pr\u00E9c\u00E9dente affiliation',\n 'Activation Date': 'La date d\\'activation',\n 'ActivationDate': 'La date d\\'activation',\n 'Sales kit required?': 'Kit de vente obligatoire?',\n 'Reset': 'R\u00E9initialiser',\n 'Create Account': 'Cr\u00E9er Utilisateur',\n 'In order to edit your name, please contact your office administrative staff, or Customer Care at 1-877-757-4545.': 'Pour changer votre nom, veuillez contacter votre \u00E9quipe administrative, ou Assistance \u00E0 la Client\u00E8le au 1-877-757-4545.',\n 'Recovery Email': 'Courriel de r\u00E9cup\u00E9ration',\n 'Communications Email': 'Courriel \u00E0 utiliser pour communiquer',\n 'Official First Name': 'Pr\u00E9nom officiel',\n 'Middle Name': 'Deuxi\u00E8me nom',\n 'Official Last Name': 'Nom de famille officiel',\n 'Salutation': 'Salutation',\n 'Title': 'Titre',\n 'Preferred Language': 'Langue pr\u00E9f\u00E9r\u00E9e',\n 'RLP Google Account': 'RLP compte Google',\n 'Preferred Email Address': 'Courriel principal',\n 'Start Date with RLP': 'Date de d\u00E9but avec RLP',\n 'RLP Start Date': 'Date de d\u00E9but avec RLP',\n 'Home Phone Number': 'Num\u00E9ro de t\u00E9l\u00E9phone',\n 'Office Phone Number': 'T\u00E9l\u00E9phone bureau',\n 'Cell Phone Number': 'Num\u00E9ro de t\u00E9l\u00E9phone cellulaire',\n 'Toll Free Phone Number': 'Num\u00E9ro de t\u00E9l\u00E9phone sans frais',\n 'Fax Number': 'Num\u00E9ro de t\u00E9l\u00E9copieur',\n 'Back Office Number': 'Num\u00E9ro d\\'arri\u00E8re-guichet',\n 'CREA ID': 'CREA ID',\n 'Centris ID': 'Centris ID',\n 'Other Locations': 'Autres bureaux',\n 'Areas Serviced': 'Zones desservies',\n 'Clear selection': 'Effacer les s\u00E9lection',\n 'Personal Website Address': 'Site Web personnel',\n 'Types of Mobile Devices': 'Types d\\'appareils mobiles',\n 'Facebook': 'Facebook',\n 'GooglePlus': 'GooglePlus',\n 'Instagram': 'Instagram',\n 'LinkedIn': 'LinkedIn',\n 'Twitter': 'Twitter',\n 'YouTube': 'YouTube',\n 'URL is invalid': 'URL est invalide',\n 'Languages Spoken': 'Langues parl\u00E9es',\n 'Specialties': 'Sp\u00E9cialit\u00E9s',\n 'Year Licensed as a Broker': 'Courtier depuis (ann\u00E9e)',\n 'Year Licensed as an Agent': 'Ann\u00E9e d\\'obtention du permis',\n 'Year of Birth': 'Ann\u00E9e de naissance',\n 'Gender': 'Sexe',\n 'Highest Level of Education': 'Niveau de scolarit\u00E9',\n 'Internal remarks': 'Remarques internes',\n 'Invalid email address.': 'Courriel invalide',\n 'First Name is a required field.': 'Le pr\u00E9nom est requis',\n 'Last Name is a required field.': 'Le nom est requis',\n 'Personnel Type is a required field.': 'Le type de personnel est requis',\n 'Preferred Language is a required field.': 'La langue pr\u00E9f\u00E9r\u00E9e est requise',\n 'RLP Google Account is a required field.': 'RLP compte Google est requis.',\n 'Input value is too long.': 'La valeur d\\'entr\u00E9e est trop longue.',\n 'Recruitment Source is a required field.': 'La source de recrutement est requise.',\n 'OACIQ ID': 'OACIQ ID',\n 'Public': 'Public',\n 'Extension': 'Extension',\n 'Year': 'Ann\u00E9e',\n 'ADD': 'Ajouter',\n '[Select]': '[S\u00E9lectionnez]',\n 'Marketing': 'MARKETING',\n 'Skills and Competencies': 'Aptitudes et comp\u00E9tences',\n 'These remarks will only show in rlpNetwork\\'s Referral Directory. Use this field to describe your professional experience, referral details and to promote and set yourself apart': 'Ces remarques s\u2019afficheront seulement sur le R\u00E9pertoire de r\u00E9f\u00E9rencement du R\u00E9seaurlp. Remplissez ce champ pour d\u00E9crire votre exp\u00E9rience professionnelle et toutes autres d\u00E9tails afin de vous promouvoir et de vous d\u00E9marquer.',\n 'Find a Guest Speaker': 'Trouver un conf\u00E9rencier',\n 'Compensation': 'R\u00E9num\u00E9ration',\n 'Speaker Bio': 'Biographie du Conf\u00E9rencier',\n 'Available to Present About': 'Disponible \u00E0 pr\u00E9senter \u00E0 propos',\n 'Willing To Travel': 'Dispos\u00E9 \u00E0 voyager',\n 'Yes': 'Oui',\n 'No': 'Non',\n 'Province': 'Province',\n 'Brokerage Name': 'Agence',\n 'Location': 'Emplacement',\n 'Contact Name': 'Nom du contact',\n 'Topic': 'Sujet',\n 'Contact Number': 'Num\u00E9ro de contact',\n 'Date': 'Date',\n 'Notes': 'Remarques',\n 'Expertise': 'Comp\u00E9tence',\n 'New Event': 'Nouvel \u00E9v\u00E8nement',\n 'Speaking Events': '\u00C9v\u00E8nements',\n 'Female': 'Femme',\n 'Male': 'Homme',\n 'All': 'Tout',\n 'INACTIVE': 'Inactif',\n 'ACTIVE': 'Actif',\n 'REACTIVATE': 'R\u00C9ACTIVER',\n 'TERMINATE': 'R\u00C9SILIER',\n 'Terminating': 'Terminaison',\n 'Reason For Leaving': 'Motif de r\u00E9siliation',\n 'End Date': 'Date de fin',\n 'Future Affiliation': 'Affiliation future',\n 'Do You Wish To Transfer Google Drive Data': 'Souhaitez-vous transf\u00E9rer les donn\u00E9es de Google Disque? ',\n 'Note: Only Google Drive Files will be transferred. Email content is not and will be only available if user is reactivated within 30 days.': 'Remarque : Seuls les fichiers pr\u00E9sents sur Google Disque sont transf\u00E9r\u00E9s. Le contenu des courriels n\u2019est pas transf\u00E9r\u00E9.',\n 'Terminate': 'R\u00C9SILIER',\n 'Future Affiliation is mandatory': 'Une affiliation future est obligatoire.',\n 'End Date is mandatory': 'La date de fin est obligatoire',\n 'Reason for Leaving is mandatory': 'La raison de partir est obligatoire',\n 'Designated user for Google Data Transfer is not selected': 'Vous n\u2019avez pas s\u00E9lectionn\u00E9 d\u2019utilisateur d\u00E9sign\u00E9 pour le transfert des donn\u00E9es de Google Disque',\n 'Future Affiliation Detail': 'D\u00E9tail de l\\'affiliation future',\n 'Reactivate Account': 'R\u00E9activer',\n 'Sales Kit Required?': 'Kit de vente obligatoire?',\n 'English': 'Anglais',\n 'French': 'Fran\u00E7ais',\n 'Previous Affiliation details': 'D\u00E9tails de l\\'affiliation pr\u00E9c\u00E9dente',\n 'View Agent Matches': 'Voir courtiers correspondants',\n 'View City/Area Serviced Matches': 'Voir villes ou zones desservies correspondantes',\n 'View Company Matches': 'Voir agences correspondantes',\n 'Total': 'Total',\n 'Filter': 'Filtre',\n 'No data found for your search': 'Aucune donn\u00E9e trouv\u00E9e pour votre recherche',\n 'Transfer Google Drive Data To': 'Transf\u00E9rer des donn\u00E9es Google Drive vers',\n 'Do you wish to transfer Google Drive Data is mandatory': 'Souhaitez-vous transf\u00E9rer les donn\u00E9es de Google Disque\u00A0est obligatoires',\n 'Invalid access': 'Acc\u00E8s invalide',\n 'Username cannot be empty': 'Nom d\\'utilisateur ne peut pas \u00EAtre vide',\n 'Username cannot contain domain': 'Nom d\\'utilisateur ne doit pas contenir le nom de domaine',\n 'Is unavailable': 'est indisponible',\n 'Is available': 'est disponible',\n 'is required.': 'est requis.',\n ' is required.': ' est requis.',\n 'First name must not exceed 50 characters.': 'Le pr\u00E9nom ne doit pas d\u00E9passer 50 caract\u00E8res',\n 'Last name must not exceed 50 characters.': 'Le nom de famille ne doit pas d\u00E9passer 50 caract\u00E8res',\n 'Email/Username must not exceed 128 characters (including domain).': 'Courriel / nom d\\'utilisateur ne doit pas d\u00E9passer 128 caract\u00E8res (domaine inclusive)',\n 'StartDate': 'Date de d\u00E9but',\n 'Password can contain only alpha-numeric characters. Remember that the password must have at least 8 characters and it should not exceed 40 characters.': 'Le mot de passe ne peut contenir que des caract\u00E8res alphanum\u00E9riques. Le mot de passe doit aussi comporter au moins 8 caract\u00E8res et un maximum 40.',\n 'Email/Username should not contain domain name.': 'Courriel / nom d\\'utilisateur ne doit pas contenir le nom de domaine.',\n 'Current Password': 'Mot de passe actuel',\n 'New Password': 'Nouveau mot de passe',\n 'Confirm Password': 'Confirmez le mot de passe',\n 'THE PASSWORD WAS SUCCESSFULLY SAVED': 'Le mot de passe a \u00E9t\u00E9 enregistr\u00E9 avec succ\u00E8s',\n 'New password and confirm password do not match': 'L\\'ancient et le nouveau mot de passe ne concorde pas',\n 'Invalid OACIQ Id': 'L\\'identifiant OACIQ n\\'est pas valide',\n 'Previous Affiliation Details must not exceed 50 characters.': 'Les d\u00E9tails de l\\'affiliation pr\u00E9c\u00E9dente ne doivent pas d\u00E9passer 50 caract\u00E8res',\n 'Delete': 'Supprimer',\n 'The user has been terminated successfully': 'Cet utilisateur a \u00E9t\u00E9 termin\u00E9 avec succ\u00E8s',\n 'The user was successfully created': 'Utilisateur Cr\u00E9\u00E9',\n 'The user has been reactivated successfully': 'Utilisateur r\u00E9activ\u00E9',\n 'Select Province First': 'Choisissez votre province',\n 'Select Brokerage First': 'Choisissez votre courtage',\n 'Award selection and Award Year is mandatory': 'Selection de prix et ann\u00E9e d\\'attribution sont obligatoire',\n 'Brokerage Name is Mandatory': 'Courtage est obligatoire',\n 'Location is Mandatory': 'Bureau est obligatoire',\n 'Topic is Mandatory': 'Sujet est obligatoire',\n 'Date is Mandatory': 'La date est obligatoire',\n 'Invalid Contact Number': 'Le num\u00E9ro de contact est invalide',\n 'Willing To Travel is mandatory': 'Dispos\u00E9\u00E0 voyager est obligatoire',\n ' is mandatory': ' est obligatoire',\n 'Current password does not match the password entered.': 'Le mot de passe actuel ne correspond pas au mot de passe saisi',\n 'Province is mandatory': 'Province est obligatoire',\n 'Brokerage is mandatory': 'Courtage est obligatoire',\n 'Click here to add details about your selection above': 'Cliquez ici pour ajouter des d\u00E9tails sur votre s\u00E9lection ci-dessus',\n '[Select Province First]': '[Choisissez votre province]',\n '[Select Brokerage First]': '[Choisissez votre courtage]',\n 'Brokerage is Mandatory': 'Courtage est obligatoire',\n 'Location is mandatory': 'Bureau est obligatoire',\n 'Invalid ': 'Invalide ',\n ' field': ' ',\n 'Other': 'Autre',\n 'OACIQ ID should be one letter followed by four numbers.': 'Le num\u00E9ro de titulaire OACIQ contient une lettre suivie de quatre chiffres.',\n 'The information was successfully saved': 'Profil mis \u00E0 jour avec succ\u00E8s.',\n 'Topic is mandatory': 'Le champs sujet est obligatoire.',\n 'No results found': 'Aucun r\u00E9sultat trouv\u00E9',\n 'Recent Speaking Events': '\u00C9v\u00E9nements r\u00E9cents',\n 'TOPICS': 'Sujets',\n 'Forgot Password Step 1': 'Mot de passe oubli\u00E9? \u00C9tape 1',\n 'Please enter your @royallepage.ca email address': 'Veuillez entrer votre courriel Royal LePage',\n 'If you do not know your Royal LePage email address, please contact your office or Customer Care to confirm your email address. If you need assistance resetting your password, please contact Customer Care. You can reach us by emailing help@royallepage.ca or calling us at 1-877-757-4545.': 'Si vous ne connaissez pas votre courriel Royal LePage, veuillez contacter votre bureau ou le Centre d\\'assistance \u00E0 la client\u00E8le pour confirmer votre courriel. Si vous avez besoin d\\'aide pour r\u00E9initialiser votre mot de passe, veuillez contacter le Centre d\\'assistance \u00E0 la client\u00E8le. Prenez contact avec nous par courriel \u00E0 aide@royallepage.ca, ou par t\u00E9l\u00E9phone au 1 877 757-4545.',\n 'Email Address/User Name not provided': 'Courriel/Nom d\\'utilisateur non fourni',\n 'Continue': 'Continuer',\n 'Forgot Password Step 2': 'Mot de passe oubli\u00E9? \u00C9tape 2',\n 'Would you like password reset instructions sent to the email address below?': 'Souhaitez-vous recevoir les instructions de r\u00E9initialisation du mot de passe \u00E0 l\u2019adresse courriel suivante?',\n 'If you no longer have access to the recovery email on file, you will need to contact Customer Care. You can reach us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545.': 'Si vous avez perdu l\u2019acc\u00E8s au courriel de r\u00E9cup\u00E9ration contenu dans vos dossiers, vous devez communiquer avec le Centre d\u2019assistance \u00E0 la client\u00E8le. Prenez contact avec nous par courriel \u00E0 aide@royallepage.ca, ou par t\u00E9l\u00E9phone au 1 877 757-4545.',\n 'Send': 'Envoyer',\n 'You do not have a recovery email on file. Please contact Customer Care. You can reach us at\u00A0help@royallepage.ca\u00A0or call 1-877-757-4545.': 'Vos dossiers ne contiennent pas de courriel de r\u00E9cup\u00E9ration. Veuillez communiquer avec le Centre d\u2019assistance \u00E0 la client\u00E8le.',\n 'Forgot Password Step 3': 'Mot de passe oubli\u00E9? \u00C9tape 3',\n 'Password reset instructions has been sent to ': 'Les instructions de r\u00E9initialisation du mot de passe ont \u00E9t\u00E9 envoy\u00E9es \u00E0 l\u2019adresse ',\n 'Remember: Changing your password here will require you to change your email password on all of your devices.': 'Rappelez-vous: pour changer votre mot de passe ici, vous devrez changer votre mot de passe de courriel sur tous vos appareils.',\n 'Go to Login Page': 'Continuer',\n 'Crop & Save': 'Rogner & Enregistrer',\n 'Drag and drop the rectangle to select the area of the photo you would like to use. When you are finished press \"Crop & Save\" or \"Cancel\" to go back to your profile.': 'Cliquer (bouton gauche de la souris) sur le rectangle de s\u00E9lection sur la photo et retener le bouton pour d\u00E9placer le r\u00E9ctangle sur la section de la photo que vous d\u00E9sirez utiliser. Lorsque vous aurez terminer, appuyer sur \"Rogner & Enregistrer\" ou \"Annuler\" pour retourner \u00E0 votre profil.',\n 'Select Date': 'S\u00E9lectionner une date',\n 'This date must be your start date with Royal LePage, and not the year you started selling real estate.': 'Cette date doit \u00EAtre la date de votre d\u00E9but avec Royal LePage et non l\\'ann\u00E9e o\u00F9 vous avez commenc\u00E9 \u00E0 vendre de l\\'immobilier.',\n 'ERROR: The photo you have selected is too big. Please select a photo that is 450 x 600 pixels or smaller.': 'ERREUR: La photo que vous avez s\u00E9lectionn\u00E9e est trop grande. Veuillez s\u00E9lectionner une photo de 450 x 600 pixels ou moins.',\n 'AWARD_INFO': '

L\\'information publi\u00E9e dans l\\'outil de suivi de distinction est fond\u00E9 sur les revenus de r\u00E9tributions brutes notari\u00E9es et encaiss\u00E9es pour l\\'ann\u00E9e de prix en cours (16 novembre au 15 novembre).

Le revenu de r\u00E9tributions brutes affich\u00E9 n\\'est pas fond\u00E9 sur des transactions en attente, mais bien sur des revenus de transactions notari\u00E9es et encaiss\u00E9es, et refl\u00E8te les donn\u00E9es les plus r\u00E9centes t\u00E9l\u00E9vers\u00E9es par l\\'agence dans le syst\u00E8me.

La taille de l\\'\u00E9quipe est d\u00E9termin\u00E9e en calculant la moyenne quotidienne du nombre de membres d\\'\u00E9quipe au cours de l\\'ann\u00E9e de prix en vigueur. Si la taille de l\\'\u00E9quipe fluctue au cours de la p\u00E9riode de reconnaissance, leurs seuils de qualification pourraient \u00E9galement changer. Les seuils de qualification sont disponibles ici.

Cet outil de suivi tient compte de l\\'\u00E9cart de 2% autoris\u00E9 par Royal LePage.

Visitez cette page pour obtenir des informations sur le programme de prix et de reconnaissance Royal LePage, ainsi que sur les lignes directrices en mati\u00E8re d\u2019\u00E9quipe.

',\n 'username': 'nomdutilisateur',\n 'Award is duplicated': 'Le prix est dupliqu\u00E9',\n 'rlpsphere': 'sphererlp',\n 'rlpNetwork_rlpSPHERE-widget-launch-en.png': 'rlpNetwork_rlpSPHERE-widget-launch-fr.png',\n 'Please select a team': 'Veuillez s\u00E9lectionner une \u00E9quipe',\n 'Team Lead': 'Chef d\u2019\u00E9quipe',\n 'Team Lead is required.': 'Chef d\u2019\u00E9quipe est requis.',\n 'Team': '\u00E9quipe',\n 'This user is not part of a team.': 'Cet utilisateur ne fait pas partie d\\'une \u00E9quipe.',\n 'none': 'aucune',\n 'Team lead can not be Admin or Licensed Assistant or Unlicensed Assistant or Finance staff.': 'Le chef d\\'\u00E9quipe ne peut \u00EAtre un administrateur, un assistant licenci\u00E9 ou un assistant non licenci\u00E9 ou Personnel des finances.',\n 'Your search returned too many results. Please refine your search.': 'Votre recherche a g\u00E9n\u00E9r\u00E9 trop de r\u00E9sultats. Veuillez affiner votre recherche.',\n 'PROFILE_LINK': '/manage-profile-fr/#/my_profile',\n 'HELP_CONTENT': 'Si vous avez un compte courriel Royal LePage, votre code d\\'utilisateur est votre adresse courriel, par exemple,\u00A0xxxxx@royallepage.ca. Si vous n\\'avez pas un compte Royal LePage, veuillez contacter votre bureau ou notre Centre d\\'assistance \u00E0 la client\u00E8le. Si vous avez besoin d\\'aide, veuillez nous rejoindre par courriel \u00E0\u00A0aide@royallepage.ca\u00A0ou par t\u00E9l\u00E9phone au 1-877-757-4545.',\n 'Business Analytics Pipeline': 'Rapports de performance',\n 'My CRM': 'Mon CRM',\n 'Sphere + Prospect': 'Sph\u00E8re + Prospect',\n 'New Lead': 'Nouveau Lead',\n 'Active Lead': 'Lead actif',\n 'Client': 'Client',\n 'Under Contract': 'Sous contrat',\n 'Closed': 'Compl\u00E9t\u00E9',\n 'Today\\'s Activities': 'Activit\u00E9s d\\'aujourd\\'hui',\n 'All Activities': 'Toutes les activit\u00E9s',\n 'Actions': 'Actions',\n 'Create a Smart Campaign': 'Cr\u00E9er une campagne intelligente',\n 'Create a Landing Page': 'Cr\u00E9er un page de destination externe',\n 'Update your rlpSPHERE Website': 'Mettre \u00E0 jour votre site Web de la SPH\u00C8RErlp',\n 'Launch': 'Lancer',\n '/manage-user/': '/gestion-dutilisateur/',\n 'Displaying': 'Affichage',\n 'End date cannot be before Start date': 'La date de fin ne peut pas \u00EAtre ant\u00E9rieure \u00E0 la date de d\u00E9but',\n 'Start Date': 'Date de d\u00E9but',\n 'If you selected Other above, please enter the agent\\'s future brokerage name here': 'Si vous s\u00E9lectionnez \u00AB Autre \u00BB, veuillez indiquer le nom de la future agence',\n 'Start date is between another period of employment': 'La date de d\u00E9but se situe entre une autre p\u00E9riode d\\'emploi',\n\n 'Manage Locations': 'Gestion des emplacements',\n 'Web and Social Media': 'Web et m\u00E9dias sociaux',\n 'Location Website Address': 'Adresse du site Web',\n 'Display Name': 'Nom affich\u00E9 publiquement',\n 'Try it': 'Essayer',\n 'Phone Number': 'Num\u00E9ro de t\u00E9l\u00E9phone',\n 'Fax': 'Num\u00E9ro de t\u00E9l\u00E9copieur',\n 'Email': 'Courriel',\n ' is invalid.': ' est invalide',\n 'Facebook is invalid.': 'Facebook est invalide',\n 'LinkedIn is invalid.': 'LinkedIn est invalide',\n 'Twitter is invalid.': 'Twitter est invalide',\n 'YouTube is invalid.': 'YouTube est invalide',\n 'Phone Number is invalid.': 'Invalide Num\u00E9ro de t\u00E9l\u00E9phone',\n 'Fax is invalid.': 'Invalide Num\u00E9ro de t\u00E9l\u00E9copieur',\n 'Email is invalid.': 'Courriel invalide',\n 'to': '\u00E0',\n 'Please submit a backup report for each agent you have flagged as potential candidates for the National Chairman\\'s Club Award and /or Top 10 Award': 'Please submit a backup report for each agent you have flagged as potential candidates for the National Chairman\\'s Club Award and /or Top 10 Award.',\n 'Upload': 'T\u00E9l\u00E9charger',\n 'Select All': 'Tout Selectionner',\n 'Click here for further guidelines': 'Cliquez ici pour plus de directives.',\n 'CONFIRM': 'CONFIRMER',\n 'Top ten candidate': 'Candidat(e) au Club des dix',\n 'An error occured. Please try again.': 'Une erreur s\\'est produite. Veuillez r\u00E9essayer!',\n 'Confirmed successfully.': 'Confirm\u00E9 avec succ\u00E8s.',\n 'Please select a location first.': 'Veuillez d\\'abord s\u00E9lectionner un emplacement',\n 'Files uploaded successfully.': 'Fichiers t\u00E9l\u00E9vers\u00E9s avec succ\u00E8s',\n 'Files uploaded unsucessfully! Please upload files again.': 'Le t\u00E9l\u00E9versement n\\'a pas fonctionn\u00E9. Veuillez essayer de nouveau.',\n 'You may adjust an agent\u2019s GCI by clicking the edit pencil and entering a positive or negative amount into the RLP Income Adjustment field next to the desired user. This will not affect your FRS invoice income as these changes are considered for awards purposes only. You will see the changes to the user\u2019s GCI reflected in the Total Awards Income field once you click out of editing mode.': 'Vous pouvez ajuster les revenus de r\u00E9tributions brutes d\u2019un courtier en cliquant sur le crayon de modification et en saisissant un montant d\u2019ajustement positif ou n\u00E9gatif dans le champ Ajustement du revenu RLP \u00E0 c\u00F4t\u00E9 de l\u2019utilisateur en question. Cela n\u2019affectera pas votre syst\u00E8me de rapports financiers (SRF), car ces changements sont consid\u00E9r\u00E9s uniquement \u00E0 des fins de distinctions. Les ajustements apport\u00E9s aux revenus de r\u00E9tributions brutes de l\u2019utilisateur seront refl\u00E9t\u00E9s dans le champ Revenu total de l\u2019ann\u00E9e de r\u00E9f\u00E9rence une fois que vous aurez quitt\u00E9 le mode de modification.',\n 'Adjusting Agent GCI': 'Ajustements des revenus de r\u00E9tributions brutes d\u2019un courtier',\n 'Adjusting Unit Count': 'Ajustement du nombre d\u2019unit\u00E9s de transaction',\n 'You may adjust the number of units allocated to an Agent by clicking on the edit pencil next to a user and entering a positive or negative number in the RLP Unit Adjustment field. You will see these changes reflected in the Total Awards Units once you click out of the editing mode.': 'Vous pouvez ajuster le nombre de transactions attribu\u00E9es \u00E0 un courtier en cliquant sur le crayon de modification \u00E0 c\u00F4t\u00E9 de l\u2019utilisateur en question et en saisissant le nombre positif ou n\u00E9gatif d\u2019ajustement \u00E0 appliquer dans le champ Ajustement des transactions RLP. Les ajustements seront refl\u00E9t\u00E9s dans le champ Nombre total de transactions de l\u2019ann\u00E9e de r\u00E9f\u00E9rence une fois que vous aurez quitt\u00E9 le mode de modification.',\n 'As a reminder, for sales awards purposes a unit is defined as follows:': '\u00C0 titre de rappel, aux fins des prix en mati\u00E8re de ventes, une unit\u00E9 de transaction est d\u00E9finie comme suit :',\n 'represents a buyer on a closed and collected deal - 1 unit': 'repr\u00E9sente un acheteur dans une transaction conclue et per\u00E7ue, cela compte comme 1 unit\u00E9 de transaction;',\n 'represents a seller on a closed and collected deal - 1 unit': 'repr\u00E9sente un vendeur dans une transaction conclue et per\u00E7ue, cela compte comme 1 unit\u00E9 de transaction;',\n 'represents both a buyer and a seller on a closed and collected deal - 2 units': 'repr\u00E9sente un acheteur et un vendeur dans une transaction conclue et per\u00E7ue, cela compte comme 2 unit\u00E9s de transaction;',\n 'co-lists or co-sells with another REALTOR\u00AE on a closed and collected deal - 1/2 unit': 'inscrit ou vend une propri\u00E9t\u00E9 avec un autre courtier immobilier dans une transaction conclue et per\u00E7ue, cela compte comme une demie unit\u00E9 de transaction;',\n 'Rentals/leases do not count as a unit [nor do referral fees earned count as a unit]': 'Les locations r\u00E9sidentielles et commerciales ne sont pas consid\u00E9r\u00E9es comme une unit\u00E9 de transaction [les commissions de r\u00E9f\u00E9rencement gagn\u00E9es ne sont pas non plus consid\u00E9r\u00E9es comme une unit\u00E9 de]',\n 'Adjusting Previous Brand Income & Units': 'Ajustement du revenu et des transactions r\u00E9alis\u00E9s ant\u00E9rieurement aupr\u00E8s d\u2019une autre banni\u00E8re',\n 'The purpose of these fields is to allow GCI and units earned within the awards year to be submitted for an agent who has joined Royal LePage from a competing brand. You may enter GCI and Units into the Previous Brand Income and Units fields in the same manner as you would for the Royal LePage income and units fields. The changes made will be reflected in the Total Award Income & Units fields once you click out of editing mode.': 'L\u2019objectif de ces champs est de permettre la soumission des revenus de r\u00E9tributions brutes et des unit\u00E9s de transaction accumul\u00E9s au cours de l\u2019ann\u00E9e de r\u00E9f\u00E9rence pour un courtier qui a quitt\u00E9 une autre banni\u00E8re pour se joindre \u00E0 Royal LePage. Vous pouvez saisir les revenus de r\u00E9tributions brutes et les transactions dans les champs concernant le revenu et les unit\u00E9s de transaction aupr\u00E8s d\u2019une banni\u00E8re pr\u00E9c\u00E9dente de la m\u00EAme mani\u00E8re que vous le feriez pour Royal LePage. Les ajustements apport\u00E9s seront refl\u00E9t\u00E9s dans les champs Nombre total d\u2019unit\u00E9s de transaction et Revenu total de l\u2019ann\u00E9e de r\u00E9f\u00E9rence une fois que vous aurez quitt\u00E9 le mode de modification.',\n 'Adjusting Income & Units for Teams': 'Ajustement des revenus et des transactions pour les \u00E9quipes',\n 'If you are adjusting the income or units for a team then you will need to adjust the income and/or units for the billing lead. If you change the income and/or units for a team member this will be considered a change to the individual\u2019s income and not the team\u2019s. If you are unsure who the billing lead is for a team please refer to the Manage Teams page.': 'Si vous ajustez les revenus ou les unit\u00E9s d\\'une \u00E9quipe, vous devrez ajuster le revenu ou le nombre d\u2019unit\u00E9s au nom du responsable de la facturation.Si vous ajustez le revenu ou le nombre d\u2019unit\u00E9s pour un membre de l\\'\u00E9quipe, cela sera consid\u00E9r\u00E9 comme un changement pour l\\'individu et non de l\\'\u00E9quipe. Si vous n\\'\u00EAtes pas s\u00FBr de savoir qui est le responsable de la facturation pour une \u00E9quipe, veuillez consulter la page G\u00E9rer les \u00E9quipes.',\n 'IMPORTANT: USERS OF LONEWOLF : VERIFYING UNIT COUNTS': 'ATTENTION : UTILISATEURS DE LONEWOLF : V\u00C9RIFICATION DU NOMBRE DE TRANSACTIONS',\n 'All trades uploaded to the FRS from BrokerWolf continue to be logged as sales transactions, even when they are not (such as leases).': 'Toutes les op\u00E9rations t\u00E9l\u00E9charg\u00E9es de BrokerWolf vers le SRF continuent d\u2019\u00EAtre enregistr\u00E9es comme des unit\u00E9s de vente, m\u00EAme si elles ne le sont pas (par exemple les baux).',\n 'This results in inflated, and inaccurate unit counts.': 'Il en r\u00E9sulte un nombre de transactions exag\u00E9r\u00E9 et inexact.',\n 'In order to accurately determine eligible units, it is ': 'Afin de d\u00E9terminer avec pr\u00E9cision les transactions \u00E9ligibles, il est ',\n 'CRITICAL': 'ESSENTIEL',\n 'verify ': 'v\u00E9rifiiez ',\n 'the unit counts for ': 'le nombre de transactions pour ',\n 'all ': 'tous ',\n 'of your sales representatives who have unit counts ': 'vos courtiers immobiliers qui affichent un nombre de transactions ',\n 'greater than 70 (greater than 60 in Alberta, Saskatchewan & Manitoba.)': '(sup\u00E9rieur \u00E0 70 (sup\u00E9rieur \u00E0 60 en Alberta, en Saskatchewan et au Manitoba.)',\n 'Even if their unit numbers are correct, you need to confirm that their numbers have been vetted.': 'M\u00EAme si le nombre d\u2019unit\u00E9s de transaction est exact, vous devez confirmer que les chiffres ont \u00E9t\u00E9 v\u00E9rifi\u00E9s.',\n 'National Chairman\u2019s Club & Top 10s: ': 'Le Club national des \u00E9lites et le Club des dix: ',\n 'The purpose of these fields is to flag users that you believe to be eligible, based on GCI and units, for one or more of these awards. If you believe the agent to be eligible for one or more of these awards simply check the box under the corresponding award. For Chairman\u2019s and Top Ten contenders it\u2019s especially important that you scroll to the bottom of the page to submit back up financials to support any change request you submitted.': 'Ces champs ont pour but de rep\u00E9rer les utilisateurs qui, selon vous, sont admissibles, en fonction des revenus de r\u00E9tributions brutes et des unit\u00E9s de transaction, \u00E0 l\u2019une ou plusieurs de ces distinctions. Si vous pensez que le courtier est admissible pour une ou plusieurs de ces distinctions, cochez simplement la case sous la distinction correspondant. Pour les candidats au Club national des \u00E9lites et au Club des dix, il est particuli\u00E8rement important de faire d\u00E9filer l\u2019\u00E9cran jusqu\u2019au bas de la page pour soumettre des donn\u00E9es financi\u00E8res \u00E0 l\u2019appui de toute demande de changement que vous avez soumise.',\n 'Close': 'Rejeter',\n 'Clicking this button confirms that all information in the form is correct and that unit counts for National Chairman\\'s Club /Top Ten Award/Top 35 Under 35 Award candidates exclude leases and referral fees received and only include units resulting from sales.': 'En cliquant sur le bouton suivant, vous confirmez que toutes les informations contenues dans le pr\u00E9sent formulaire sont v\u00E9ridiques et que les unit\u00E9s soumises pour le classement de vos candidats au Club national des \u00E9lites, Club des 10 et Top 35 des moins de 35 exclues les locations et les r\u00E9f\u00E9rences, pour n\\'inclure que les unit\u00E9s reli\u00E9es \u00E0 une vente.',\n 'Please submit a backup report for each agent you have flagged as potential candidates for the National Chairman\\'s Club Award and /or Top 10 Award.': 'Si vous avez indiqu\u00E9 des candidats potentiels au Club national des \u00E9lites et au Club des 10, veuillez soumettre les rapports de ventes ici.',\n 'Confirmed successfully!': 'Confirm\u00E9 avec succ\u00E8s !',\n 'For users returning or joining from another Royal LePage brokerage, please select \"REACTIVATE USER\".': 'Pour les utilisateurs qui reviennent d\\'un cong\u00E9 prolong\u00E9 ou d\\'une autre agence Royal LePage, veuillez cliquer sur le bouton \u00AB R\u00C9ACTIVER \u00BB.',\n 'For new users, please continue and select \"CREATE NEW USER\".': 'Pour les nouveaux utilisateurs, veuillez continuer et s\u00E9lectionner \u00AB NOUVEL UTILISATEUR \u00BB.',\n 'REACTIVATE USER': 'R\u00C9ACTIVER',\n 'CREATE NEW USER': 'NOUVEL UTILISATEUR',\n 'ROYAL LEPAGE is a registered trademark of Royal Bank of Canada and is used under licence by Bridgemarq Real Estate Services Inc. and Bridgemarq Real Estate Services Manager Limited.': 'ROYAL LEPAGE est une marque de commerce d\u00E9pos\u00E9e de la Banque Royale du Canada, utilis\u00E9e sous license par Bridgemarq Real Estate Services Inc. et Bridgemarq Real Estate Services Manager Limited.',\n 'based on': 'en',\n 'GCI': 'revenu brut',\n 'Units': 'unit\u00E9s',\n 'GCI & Units': 'revenu brut et unit\u00E9s',\n 'Important Reminder': 'Rappel important',\n 'TEAM MEMBERS: team member trades that were written BEFORE the member joined the team CANNOT be added to the team lead for sales awards purposes since it is business written BEFORE joining the team.This income may be used by the team member to qualify for an individual award.': 'MEMBRES D\u2019\u00C9QUIPE: les transactions conclues par un courtier avant qu\u2019il ne se joigne \u00E0 l\u2019\u00E9quipe NE PEUVENT PAS \u00EAtre ajout\u00E9s aux revenus de l\u2019\u00E9quipe (donc du chef d\u2019\u00E9quipe). Les revenus g\u00E9n\u00E9r\u00E9s par le courtier avant qu\u2019il ne travaille en \u00E9quipe seront consid\u00E9r\u00E9s pour un prix individuel pour ce m\u00EAme courtier.',\n 'IMPORTANT: USERS OF LONEWOLF (and EzMax & Nexone in Quebec)': 'IMPORTANT',\n 'VERIFYING UNIT COUNTS FOR EVERY AGENT': 'V\u00C9RIFICATION DES UNIT\u00C9S DE TRANSACTIONS',\n 'All trades uploaded to the FRS from BrokerWolf continue to be logged as sales transactions, even when they are not sales.': 'Plusieurs op\u00E9rations t\u00E9l\u00E9charg\u00E9es vers le SRF continuent d\u2019\u00EAtre enregistr\u00E9es comme des unit\u00E9s de vente, m\u00EAme si elles ne le sont pas (par exemple les baux).',\n 'In order to accurately determine eligible units, it is CRITICAL that you verify the unit counts for all of your sales representatives.':\n 'Afin de d\u00E9terminer avec pr\u00E9cision les transactions \u00E9ligibles, il est ESSENTIEL que vous v\u00E9rifiez le nombre de transactions pour tous vos courtiers immobiliers susceptibles de se qualifier aux Tops 2%, 5% et 10% national, donc qui affichent un nombre de transactions \u00E9gal ou sup\u00E9rieur \u00E0 20.'\n , 'EXCEL': 'EXCEL',\n 'Password is a required field. Remember that the password must have at least 8 characters and it should not exceed 40 characters. The Password must contain at least one uppercase letter, one lowercase letter, one digit and one special character': 'Mot de passe est un champ obligatoire. N\\'oubliez pas que le mot de passe doit comporter au moins 8 caract\u00E8res et ne doit pas d\u00E9passer 40 caract\u00E8res. Il doit contenir au moins une lettre majuscule, une lettre minuscule, un chiffre et un caract\u00E8re sp\u00E9cial.',\n 'Change Password': 'Changer le mot de passe',\n 'Your password has been changed successfully.': 'Votre mot de passe a \u00E9t\u00E9 chang\u00E9 avec succ\u00E8s.',\n 'Error resetting password': 'Erreur lors de la r\u00E9initialisation du mot de passe',\n 'Invalid Password': 'Mot de passe incorrect',\n 'Password and Confirm Password do not match': 'Le mot de passe et le mot de passe de confirmation ne correspondent pas',\n '/customer-care-centre/': '/assistance-a-la-clientele/',\n 'Team Member Start Date': 'Date de d\u00E9but du membre de l\\'\u00E9quipe',\n 'Team Member End Date': 'Date de fin du membre de l\\'\u00E9quipe',\n 'Billing Lead': 'Responsible for billing',\n 'Launch RoyalMag': 'Lancer la RayalMag',\n\n 'Password must have at least 8 characters and it must not exceed 40 characters.': 'Le mot de passe doit comporter au moins 8 caract\u00E8res et ne doit pas d\u00E9passer 40 caract\u00E8res.',\n 'Password must contain at least one uppercase letter.': 'Le mot de passe doit contenir au moins une lettre majuscule.',\n 'Password must contain at least one lowercase letter.': 'Le mot de passe doit contenir au moins une lettre minuscule.',\n 'Password must contain at least one digit.': 'Le mot de passe doit contenir au moins un chiffre.',\n 'Password must contain at least one special character.': 'Le mot de passe doit contenir au moins un caract\u00E8re sp\u00E9cial.',\n 'Confirm Password must be same as New Password.': 'Le mot de passe de confirmation doit \u00EAtre identique au nouveau mot de passe.',\n 'Invalid New Password, The password must have at least 8 characters and it should not exceed 40 characters. The Password must contain at least one uppercase letter, one lowercase letter, one digit and one special character.': 'Mot de passe incorrect. Le mot de passe doit comporter au moins 8 caract\u00E8res et ne doit pas d\u00E9passer 40 caract\u00E8res. Il doit contenir au moins une lettre majuscule, une lettre minuscule, un chiffre et un caract\u00E8re sp\u00E9cial.',\n 'Password may not contain username, first name or last name.': 'Le mot de passe ne doit pas contenir le nom d\\'utilisateur, le pr\u00E9nom ou le nom de famille.',\n 'X (Formerly Twitter)': 'X (anciennement Twitter)',\n 'Home':'Accueil',\n 'of': 'de',\n 'results': 'r\u00E9sultats',\n 'https://docs.rlpnetwork.com/rlpNetwork/Networking/GuestSpeaker/Find_a_Guest_Speaker_Resources_EN.pdf':'https://docs.rlpnetwork.com/rlpNetwork/Networking/GuestSpeaker/Find_a_Guest_Speaker_Resources_FR.pdf',\n 'Click Here':'Cliquez ici',\n 'for resources and tips on filling out your Guest Speaker Profile':'pour des ressources et des conseils pour remplir votre profil sur le r\u00E9pertoire des conf\u00E9renciers',\n 'home': 'accueil',\n 'Royal LePage\u00AE is a registered trademark of Royal Bank of Canada and is used under licence by Bridgemarq Real Estate Services\u00AE. View important disclosures and notices about trademarks at rlp.ca/notices.':'Royal LePageMD est une marque de commerce d\u00E9pos\u00E9e de la Banque Royale du Canada, utilis\u00E9e sous licence par les Services Immobiliers BridgemarqMD. Consultez les divulgations et les avis importants concernant les marques ici rlp.ca/avisjuridiquesetdecharges.',\n 'rlpNetworkTM': 'R\u00E9seaurlpMC',\n 'Delete my Guest Speaker Profile': 'Supprimer mon profil de conf\u00E9rencier',\n 'My Speaker\\'s Spotlight Video Link':'Le lien vid\u00E9o de mon profil de conf\u00E9rencier',\n 'References':'R\u00E9f\u00E9rences',\n 'All information is required in references':'Veuillez fournir toutes les informations requises pour les r\u00E9f\u00E9rences',\n 'Areas of Expertise': 'Domaines d\\'expertise',\n 'Speaker\\'s Spotlight':'Projecteur sur les orateurs',\n\n 'January': 'janvier',\n 'February': 'f\u00E9vrier',\n 'March': 'mars',\n 'April': 'avril',\n 'May': 'mai',\n 'June': 'juin',\n 'July': 'juillet',\n 'August': 'ao\u00FBt',\n 'September': 'septembre',\n 'October': 'octobre',\n 'November': 'novembre',\n 'December': 'd\u00E9cembre',\n 'Total Year': 'ann\u00E9e totale',\n 'Month': 'Mois',\n\n 'Live': 'Donn\u00E9es en direct',\n 'Invoice': 'Information sur la facture',\n\n 'Display Name should be the same name as registered with your provincial professional association.':'Le nom d\u2019affichage doit \u00EAtre le m\u00EAme nom que celui enregistr\u00E9 aupr\u00E8s de votre association professionnelle provinciale.',\n 'Personal Corporation' : 'Soci\u00E9t\u00E9 par actions',\n 'One or more back office numbers are invalid or duplicate.':'Un ou plusieurs num\u00E9ros du back office sont invalides ou en double.',\n 'Google Sign In Failed':'\u00C9chec de la connexion Google',\n 'Unable to initiate Google sign in':'Impossible de lancer la connexion Google',\n 'Sign in with Google':'Se connecter avec Google'\n\n }\n};\n", "const DEFAULT_LANGUAGE = 'en';\nimport dict from './dict.json';\n\nexport let lang = document.cookie.replace(/(?:(?:^|.*;\\s*)pll_language\\s*=\\s*([^;]*).*$)|^.*$/i, '$1') || 'en';\n\nexport const setLanguage = (value, name = 'pll_language') => {\n lang = value;\n document.cookie = `${name}=${value || ''};path=/`;\n};\n\nexport default (text, ...args) => {\n let txt = (lang && dict[lang] && dict[lang][text]) || (lang === DEFAULT_LANGUAGE ? text: `${text}*`);\n\n let n = 0;\n while (txt.indexOf('%') > 0) {\n txt = txt.replace('%', args[n++] || '');\n }\n\n return txt;\n};\n\nexport const __ = (text) => {\n const txt = (lang && dict[lang] && dict[lang][text]) || (lang === DEFAULT_LANGUAGE ? text: `${text}*`);\n return txt;\n};", "import app from 'apprun';\nimport _, { lang } from '../l10n';\n\ndeclare let $;\nconst link = lang === 'en' ? ('https://www.youtube.com/embed/af3rVgITqCs') : ('https://www.youtube.com/embed/bynUkDrDRPU');\n\nconst Errors = ({ msg, detail }) => {\n return (\n
\n
\n \n {_('The following errors have occurred')}\n
\n

{_(msg)}

\n
    \n
  • \n \n \n \n {_(detail)}\n
  • \n
\n
\n );\n};\n\nexport const ResetPasswordView = ({ state, mainComponent }) => {\n return (\n
\n
\n
\n
\n \n {_('Your password has been changed successfully.')}\n {\n mainComponent.run('sign-in-loading', e);\n mainComponent.run('#sign-in', e);\n }}\n value=\"\"\n />\n {\n mainComponent.run('sign-in-loading', e);\n mainComponent.run('resetpassword-sign-in', e);\n }}>\n \n {_('Login')}\n \n
\n\n \n
\n
\n {state.error.msg ? : ''}\n
\n {/*
\n {_('Password is a required field. Remember that the password must have at least 8 characters and it should not exceed 40 characters.')}\n
*/}\n
\n
\n \n mainComponent.run('new-pwd-changed')}\n onfocus={() => mainComponent.run('new-pwd-changed')}\n // onblur={e => mainComponent.run('validatePassword', e)}\n />\n
\n
\n \n mainComponent.run('new-pwd-changed')}/>\n
\n
\n
\n
    \n
  • {_('Password must have at least 8 characters and it must not exceed 40 characters.')}
  • \n
  • {_('Password must contain at least one uppercase letter.')}
  • \n
  • {_('Password must contain at least one lowercase letter.')}
  • \n
  • {_('Password must contain at least one digit.')}
  • \n
  • {_('Password must contain at least one special character.')}
  • \n
  • {_('Confirm Password must be same as New Password.')}
  • \n
\n
\n
\n
\n
\n \n mainComponent.run('changePassword', $('#password').val(), $('#confirmPassword').val())\n }\n class=\"btn btn-rlp btn-block pull-right-lg\">\n \n {_('Change Password')}\n \n
\n
\n
\n
\n
\n
\n \n );\n};\nexport const LoginView = ({ state, mainComponent, textMessage }) => {\n return (\n
\n
\n
\n
\n
\n
\n
\n {state.error.msg ? : ''}\n {\n mainComponent.run('sign-in-loading', e);\n mainComponent.run('sign-in', e);\n }}>\n
\n \n \n
\n
\n \n \n
\n
\n
\n \n
\n
\n mainComponent.run('toggleFlag', 'state.forgotPasswordStep1', e)}\n class=\"btn btn-rlp btn-rlp-inverse btn-block pull-right-lg\">\n \n {_('Forgot Password')}\n \n
\n {/*
\n mainComponent.run('google-sign-in', e)}\n class=\"btn btn-block\"\n style={{\n backgroundColor: '#ffffff',\n border: '1px solid #dadce0',\n color: '#3c4043',\n fontFamily: 'Roboto, sans-serif',\n height: '40px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center'\n }}>\n \n {_('Sign in with Google')}\n \n
*/}\n
\n \n
\n
\n
\n
\n
\n

{_('Work Faster.Work Smarter.rlpNetwork.')}

\n
\n