UNPKG

@kiwicom/smart-faq

Version:

Smart FAQ

549 lines (497 loc) 15.7 kB
// @flow /* eslint-disable import/no-extraneous-dependencies, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions, no-console */ import React from 'react'; import ReactDOM from 'react-dom'; import Cookies from 'js-cookie'; import Raven from 'raven-js'; import SmartFAQApp from './SmartFAQApp'; import ContactFormChatApp from './ContactFormChatApp'; import CustomerSupportPhones from './CustomerSupportPhones'; import { Requester } from './staging/Requests'; import type { User } from './types'; import { loadStaticTranslations } from './shared/helpers/translationUtils'; import brandConfigs from '../static/brands.json'; import LoginModal from './staging/LoginModal'; type Props = {||}; type State = {| showLoginModal: boolean, showPhoneLines: boolean, isClosable: boolean, user: User, loginToken: ?string, kwAuthToken: string, simpleToken: string, helpQuery: ?string, showEmergencies: boolean, showBooking: boolean, showPriorityLine: boolean, enableChat: boolean, forceChat: boolean, brand: string, language: string, translations: { [key: string]: string }, languageDirection: string, bid: ?number, |}; const user = { id: '1', email: 'joe.doe@example.com', firstname: 'Joe', lastname: 'Doe', }; const emergencies = [ 'Because of the middle age ways how to get to Prague Airport and all donkeys are at strike, we are receiving far more contacts than usual. Please solve your request in our shiny mobile app.', 'The political unrest in Catalan republic has affected many flights and we are experiencing a high number of contacts. Please departure to Belgium to avoid prison.', ]; const chatConfig = { CHAT_GUID: process.env.CHAT_GUID || '', CHAT_DEPLOYMENT_KEY: process.env.CHAT_DEPLOYMENT_KEY || '', CHAT_ORG_ID: process.env.CHAT_ORG_ID || '', CHAT_QUEUE_NAME: process.env.CHAT_QUEUE_NAME || 'CHAT TEST', }; class Root extends React.Component<Props, State> { input: ?HTMLInputElement; constructor(props) { super(props); const loginToken = Cookies.get('loginToken'); const simpleToken = Cookies.get('simpleToken'); const kwAuthToken = Cookies.get('kwAuthToken'); const forceChat = sessionStorage.getItem('forceChat'); window.GuaranteeChatForce = forceChat ? Boolean(parseInt(forceChat)) : false; // helpers for cypress const paramsString = window.location.search; const params = new URLSearchParams(paramsString); const helpQueryString = params.get('help'); const enableChat = Cookies.get('enableChat') ? Boolean(parseInt(Cookies.get('enableChat'))) : true; const showEmergencies = Cookies.get('showEmergencies') ? Boolean(parseInt(Cookies.get('showEmergencies'))) : false; const showBooking = Cookies.get('showBooking') ? Boolean(parseInt(Cookies.get('showBooking'))) : true; const bid = Cookies.get('selectedBooking') ? Number(Cookies.get('selectedBooking')) : null; const brand = Cookies.get('brand') || 'kiwicom'; this.state = { isClosable: true, user: loginToken ? user : null, loginToken, simpleToken, kwAuthToken, enableChat, showPriorityLine: true, forceChat: window.GuaranteeChatForce, showEmergencies, showLoginModal: false, showBooking, helpQuery: helpQueryString ? helpQueryString : '/', brand, language: 'en', translations: loadStaticTranslations('en'), languageDirection: 'ltr', bid, showPhoneLines: false, }; this.setupLogs(); } componentDidMount() { window.addEventListener('keydown', this.onKeyDown); } componentWillUnmount() { window.removeEventListener('keydown', this.onKeyDown); } onKeyDown = e => { if (e.noInputFocus) { return; } this.input && this.input.focus(); }; onToggleChat = () => { this.setState(({ enableChat }) => ({ enableChat: !enableChat })); }; onForceChat = () => { if (typeof window === 'undefined') { return; } const forceChat = !window.GuaranteeChatForce; sessionStorage.setItem('forceChat', forceChat ? '1' : '0'); window.GuaranteeChatForce = forceChat; this.setState({ forceChat }); }; setupLogs = () => { if ( process.env.NODE_ENV === 'production' && process.env.SENTRY_URL_STAGING ) { window.Raven = Raven; Raven.config(process.env.SENTRY_URL_STAGING).install(); } }; processLogin = async (email: string, password: string) => { if (!(email && password)) { console.error('Testing user not set in env vars.'); return; } const loginToken = await Requester.login( email, password, '', this.state.brand, ); Cookies.set('loginToken', loginToken); window.location.reload(); }; handleLogin = () => { this.setState({ showLoginModal: true }); }; handleLogout = async () => { this.setState({ user: null, loginToken: null, simpleToken: '', kwAuthToken: '', }); Cookies.remove('loginToken'); Cookies.remove('simpleToken'); Cookies.remove('kwAuthToken'); }; handleAppWithOpenChatClose = (isClosable: boolean) => { this.setState({ isClosable }); }; handleBidChange = e => { const value = e.target.value; const bid = value ? Number(value) : null; this.setState({ bid: Number.isFinite(bid) ? bid : null }); }; handleTokenChange = e => { this.setState({ simpleToken: e.target.value }); }; handleKwTokenChange = e => { this.setState({ kwAuthToken: e.target.value }); }; toggleApp = () => { this.setState(({ helpQuery }) => ({ helpQuery: helpQuery ? null : '/' })); }; closeApp = () => { if (!this.state.isClosable) { const canClose = window.confirm( 'Closing this window will cause the chat connection to be interrupted, do you want to proceed?', ); if (!canClose) { return; } } this.setState({ helpQuery: null }); }; toggleEmergencies = () => { this.setState(({ showEmergencies }) => ({ showEmergencies: !showEmergencies, })); }; toggleBooking = () => { this.setState(({ showBooking }) => ({ showBooking: !showBooking })); }; togglePhonesList = () => { this.setState(({ showPhoneLines }) => ({ showPhoneLines: !showPhoneLines, })); }; togglePriorityLine = () => { this.setState(({ showPriorityLine }) => ({ showPriorityLine: !showPriorityLine, })); }; changeLanguage = (e: SyntheticInputEvent<HTMLInputElement>) => { const language = e.target.value; this.setState({ language, translations: loadStaticTranslations(language) }); }; changelanguageDirection = (e: SyntheticInputEvent<HTMLInputElement>) => { this.setState({ languageDirection: e.target.value }); }; changeBrand = (e: SyntheticInputEvent<HTMLInputElement>) => { const brand = e.target.value; this.setState({ brand }); Cookies.set('brand', brand); }; render() { const { helpQuery, showEmergencies, language, languageDirection, brand, showLoginModal, showPhoneLines, } = this.state; const brandConfig = brandConfigs[brand] || brandConfigs['kiwicom']; return ( <div> {showLoginModal && ( <LoginModal onSubmit={(email, password) => this.processLogin(email, password)} onClose={() => this.setState({ showLoginModal: false })} /> )} <div className="toggler" onKeyUp={() => {}} role="button" tabIndex="-1" onClick={this.toggleApp} > Toggle SmartFAQ </div> <div className="mockedMainView"> <div> <h3>Show some emergencies</h3> <input type="checkbox" checked={showEmergencies} onChange={this.toggleEmergencies} /> <h3>Enable booking screen</h3> <input type="checkbox" checked={this.state.showBooking} onChange={this.toggleBooking} /> <h3>Enable chat</h3> <input type="checkbox" checked={this.state.enableChat} onChange={this.onToggleChat} /> <h3>Force chat to be always available</h3> <input type="checkbox" onChange={this.onForceChat} checked={this.state.forceChat} /> <h3>Show Customer Support Phones List</h3> <input type="checkbox" onChange={this.togglePhonesList} checked={this.state.showPhoneLines} /> <br /> <label htmlFor="priorityLine"> show priority line <input id="priorityLine" type="checkbox" onChange={this.togglePriorityLine} checked={this.state.showPriorityLine} /> </label> <h3>Set BID & simple token for debugging.</h3> <input onChange={this.handleBidChange} value={this.state.bid || ''} placeholder="BID" /> <input onChange={this.handleTokenChange} value={this.state.simpleToken} placeholder="Simple token" /> <div> <h3>Set KW-Auth-Token for debugging.</h3> <input onChange={this.handleKwTokenChange} value={this.state.kwAuthToken} placeholder="KW-Auth-Token" /> </div> <h3>Change languages</h3> <label htmlFor="en-GB"> <input type="radio" value="en" id="en-GB" checked={language === 'en'} onChange={this.changeLanguage} /> English(en-GB) </label> <label htmlFor="es-ES"> <input type="radio" value="es" id="es-ES" checked={language === 'es'} onChange={this.changeLanguage} /> Spanish(es-ES) </label> <label htmlFor="cs-CZ"> <input type="radio" value="cz" id="cs-CZ" checked={language === 'cz'} onChange={this.changeLanguage} /> Czech(cs-CZ) </label> <h3>Change brand</h3> <label htmlFor="kiwicom"> <input type="radio" value="kiwicom" id="kiwicom" checked={brand === 'kiwicom'} onChange={this.changeBrand} /> Kiwi.com </label> <label htmlFor="visitberlin"> <input type="radio" value="visitberlin" id="visitberlin" checked={brand === 'visitberlin'} onChange={this.changeBrand} /> Visit Berlin </label> <label htmlFor="holidaypirates"> <input type="radio" value="holidaypirates" id="holidaypirates" checked={brand === 'holidaypirates'} onChange={this.changeBrand} /> Holiday Pirates </label> <h3>Change from LTR to RTL languages</h3> <label htmlFor="LTR"> <input type="radio" value="ltr" id="LTR" checked={languageDirection === 'ltr'} onChange={this.changelanguageDirection} /> LTR </label> <label htmlFor="RTL"> <input type="radio" value="rtl" id="RTL" checked={languageDirection === 'rtl'} onChange={this.changelanguageDirection} /> RTL </label> </div> <div> <ContactFormChatApp.BookingInfoProvider value={{ onLoad: leg => console.log(leg) }} > <ContactFormChatApp language={language} brand={this.state.brand} translations={null} chatConfig={chatConfig} loginToken={this.state.loginToken} simpleToken={this.state.simpleToken} kwAuthToken={this.state.kwAuthToken} bid={this.state.bid} enableChat={this.state.enableChat} /> </ContactFormChatApp.BookingInfoProvider> </div> <div> {showPhoneLines && ( <CustomerSupportPhones language={language} showPriorityLine={this.state.showPriorityLine} translations={this.state.translations} linkToLearnMoreArticle={() => undefined} /> )} </div> </div> {helpQuery && ( <div className="sidebarOverlay" onClick={this.closeApp} /> )} <div className="sidebar" dir={languageDirection}> <SmartFAQApp onClose={this.closeApp} onLogin={this.handleLogin} onLogout={this.handleLogout} translations={this.state.translations} language={language} direction={languageDirection} brandConfig={brandConfig} brand={this.state.brand} user={this.state.user} route={helpQuery} bid={this.state.bid} showBooking={this.state.showBooking} loginToken={this.state.loginToken} simpleToken={this.state.simpleToken} kwAuthToken={this.state.kwAuthToken} enableChat={this.state.enableChat} chatConfig={chatConfig} onToggleIsClosable={this.handleAppWithOpenChatClose} emergencies={showEmergencies ? emergencies : []} isChatActive={!this.state.isClosable} /> </div> <style jsx global> {` .sidebar { position: fixed; right: 0; top: 0; } .sidebarOverlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); } .mockedMainView { margin-top: 100px; display: flex; } .toggler { position: fixed; top: 20px; left: 20px; cursor: pointer; color: white; border: 3px solid green; padding: 5px; outline: none; background: green; } `} </style> </div> ); } } (() => { const root = document.createElement('div'); root.setAttribute('id', 'root'); if (!document.body) { throw new Error('No browser?'); } document.body.appendChild(root); const id = document.getElementById('root'); if (!id) { throw new Error('Root element is missing!'); } ReactDOM.render(<Root />, id); })();