{"version":3,"sources":["constants/device-sizes.js","hooks/useKeyPress.js","constants/deviceType.js","constants/message-constants.js","components/roomInputText.jsx","utils/geometry.js","components/ventMessage.jsx","components/messagesContainer.jsx","utils/localstorage.js","constants/string-constants.js","components/onlineCounter.jsx","components/roomButtonsContainer.jsx","components/roomHeader.jsx","components/settingsMenu.jsx","components/room.jsx","components/roomListItem.jsx","components/header.jsx","components/roomsMenu.jsx","store/container-actions.js","store/onboarding-actions.js","store/messages-actions.js","hooks/useOnboardingTooltip.js","components/v2/Message.jsx","components/v2/MessagesContainer.jsx","components/v2/input/InputBox.jsx","components/v2/input/SubmitButton.jsx","components/v2/input/InputContainer.jsx","hooks/useWindowSize.js","components/v2/input/IOSInputContainer.jsx","components/v2/input/InputBar.jsx","components/v2/ModalButton.jsx","components/v2/TitleText.jsx","components/v2/PhoneSignUpModal.jsx","components/v2/SettingsMenu.jsx","hooks/useComponentRect.js","store/ui-actions.js","components/v2/ButtonContainer.jsx","components/v2/debug/HighlightedComponents.jsx","components/v2/debug/DisplayRandomMessages.jsx","components/v2/ReachOutModal.jsx","components/v2/OnboardingModal.jsx","components/v2/RoomV2.jsx","store/messages-reducer.js","store/container-reducer.js","store/ui-reducer.js","store/onboarding-reducer.js","App.js","reportWebVitals.js","index.js"],"names":["size","device","mobileS","mobileM","mobileL","tablet","laptop","laptopL","desktop","desktopL","isMobile","window","innerWidth","useKeyPress","key","action","useEffect","onKeyup","e","addEventListener","removeEventListener","isiOSDevice","includes","navigator","platform","userAgent","document","InputContainer","styled","div","input","ArrowCircleUp","RoomInputText","getPositionForNewDiv","newDiv","currentDivs","boundingRect","pos","partitionAlgorithm","verifyDivPos","DOMRect","width","height","outerBoundingRect","depth","rect1","rect2","midPoint","top","left","rect1Stack","rect2Stack","rect1TIS","rect2TIS","doRectanglesIntersect","push","rectIntersectionArea","rect1FilledProportion","rect2FilledProportion","Math","random","placeDivInCorner","nearestLeft","nearestRight","right","nearestTop","nearestBottom","bottom","centerX","centerY","isOnLeftSide","isOnTopSide","newleft","newtop","leftDFromEdge","rightDFromEdge","topDFromEdge","bottomDFromEdge","outerRight","max","outerBottom","tryCount","console","log","min","a","b","VentDiv","React","PureComponent","MessagesContainer","DARK_MODE_KEY","ONBOARDING_SHOWN_KEY","ONBOARDING_INDEX","BLOCK_LIST_KEY","darkModeEnabled","readDarkModePreference","inMemoryBlockList","getBlockList","saveDarkModePreference","localStorage","setItem","JSON","stringify","getItem","matchMedia","matches","parse","toggleDarkMode","enableDarkMode","getOnboardingIndex","onboardingIndex","documentElement","style","setProperty","storageItem","Set","API_URL","process","REACT_APP_API_URL","props","marginBottom","Users","span","OnlineCounter","Cog","h2","RoomHeader","isOpen","Times","ul","li","Room","h3","type","p","button","RoomListItem","Header","RoomsMenu","UPDATE_CONTAINER","INCREMENT_ONBOARDING","ASSIGNED_TOOLTIP_TO_MESSAGE","ADD_MESSAGE","DELETE_MESSAGE","UPDATE_MESSAGE","UPDATE_MESSAGES","CACHE_MESSAGE","POP_MESSAGE","MESSAGE_STATUS_NEW","MESSAGE_STATUS_CACHED","emojiRegex","regex","deleteMessage","id","payload","createMessage","message","dispatch","getState","messageCountMultiplier","messageLengthMultiplier","messages","Object","values","byId","length","messageText","singleEmojiMultiplier","Array","from","matchAll","m","adminSizeMultiplier","sizeMultiplier","BASE_FONT_SIZE","parseFloat","getComputedStyle","getPropertyValue","fontSize","ceil","finalSize","isFinite","rect","triggerFadeOut","onboarding","needsMessage","tooltipDisabled","index","addMessage","moveMessage","ui","containerRect","find","msg","initialRect","ratio","leftInset","rightInset","topInset","bottomInset","existingMessages","map","filter","existingRects","concat","getElementsByClassName","getBoundingClientRect","err","error","newX","newY","messageCountModifier","messageTypeModifier","status","fadeOutDuration","updateMessage","removeMessage","cacheMessage","useOnboardingTooltip","ref","useState","setTooltipDisabled","hasShown","setHasShown","useSelector","state","setTimeout","ReactTooltip","show","current","hide","bez","$","Text","color","bold","DateText","Container","BlockButton","Message","useDispatch","setSize","messageMoved","setMessageMoved","blockButtonVisible","setBlockButtonVisible","messageRef","useRef","createdAt","useLayoutEffect","clientWidth","clientHeight","fadeTo","data-tip","onboardingMessage","data-tip-disable","data-place","onMouseOver","stop","onMouseOut","opacity","onClick","userId","moment","fromNow","blockedUserId","newBlock","blockList","add","addToBlockList","filteredMessages","sendBlockedUserToServer","messagePropsAreEqual","prevMessage","nextMessage","memo","containerRef","setRect","handleResize","visualViewport","innerHeight","offsetTop","prevState","nextState","Input","InputBox","forwardRef","autoFocus","autoComplete","autoCorrect","placeholder","maxLength","tabIndex","disabled","value","onChange","event","target","onFocus","onBlur","Button","PaperPlane","enabled","SubmitButton","onSubmit","onMouseDown","preventDefault","standalone","inputText","setInputText","inputBox","submitMessage","sendMessage","text","useWindowSize","undefined","windowSize","setWindowSize","windowWidth","windowHeight","visualViewportHeight","MockContainer","z_index","transition","IOSInputContainer","inputFocused","setInputFocused","inputActive","setInputActive","inputActiveSwitch","setInputActiveSwitch","iOSInputBox","styles","prevVVH","setRefs","handleVisibilityChange","visibilityState","blur","scrollTo","Fragment","focus","InputBar","executeRecaptcha","useGoogleReCaptcha","then","token","catch","isIOSDevice","ContinueButton","isAffirmative","ButtonText","Indicator","ModalButton","theme","children","isLoading","Title","TitleText","ModalSC","Modal","ModalContent","Description","ALT_TEXT_COLOR","ButtonContainer","PhoneInputContainer","PhoneInput","MODAL_INPUT_BACKGROUND","TEXT_COLOR","Page","Dropdown","ErrorText","ModalButtonSC","CodeInput","ReactCodeInput","PhoneSignUpModal","phoneNumber","setPhoneNumber","confirm","setConfirm","continueEnabled","setContinueEnabled","setLoading","verificationCodeText","setVerificationCodeText","errorText","setErrorText","selectedCountry","setSelectedCountry","phoneInput","codeField","curPage","setCurPage","whiteListedPhoneNumber","captchaRef","getAuth","currentUser","getIdToken","fetch","replace","method","headers","Authorization","result","json","responseJson","phoneNumberFound","setFocus","viewRef","delay","fullPhoneNumber","auth","recaptcher","RecaptchaVerifier","callback","response","setPersistence","browserLocalPersistence","signInWithPhoneNumber","confirmation","code","verify","onSuccess","onClose","initPn","pn","PhoneNumber","isValid","checkPhoneWhitelist","visible","countryPickerOptions","label","onBackgroundClick","collapsable","options","option","onInput","keyboardType","autoCompleteType","fields","fieldWidth","as","CloseButton","SettingsList","SettingsItem","SettingsMenu","darkModeButton","closeSettingsMenu","analytics","getAnalytics","logEvent","openInstructions","innerText","href","rel","referrer","useComponentRect","componentRect","setComponentRect","UPDATE_UI","Wrapper","ReplayButton","UndoAlt","replaying","SettingsButton","Recycle","recycling","OnlineIndicatorContainer","connected","settingsRef","uiRect","onClickReplay","onClickSettings","place","DisplayRandomMessages","ReachOutModal","SubTitle","OnboardingModal","RoomContainer","RoomV2","modalIsOpen","setModalIsOpen","reachOutModalOpen","setReachOutModalOpen","onboardingModalOpen","setOnboardingModalOpen","settingsMenuIsOpen","setSettingsMenuIsOpen","roomRef","hasAlreadySignedIn","socket","messageQueue","historicalMessages","setConnected","sendEnabled","setSendEnabled","setReplaying","setRecycling","messagesSentCount","onboardingInfo","displayQueueMessage","curQueue","interval","shift","has","registerUser","substring","body","push_notification_token","strippedMessage","registerUserAndConnectToSocket","user","connectToSocket","reconnect","disconnect","io","on","getElementById","addHistoricalMessage","prev","emit","getLanguage","warning","time","historicalMessagesFromBackend","language","userLanguage","realClick","randomMessages","disableBodyScroll","onAuthStateChanged","signInAnonymously","setInterval","clearInterval","reCaptchaKey","position","autoClose","hideProgressBar","newestOnTop","closeOnClick","rtl","pauseOnFocusLoss","draggable","pauseOnHover","nextOpenState","open","onClickRecycle","uuidv4","messageLength","toast","info","progress","combineReducers","updateMessagesState","forEach","removeMessagesState","allIds","cached","slice","initialState","messageToolTipIndexes","rootReducer","messagesReducer","store","createStore","applyMiddleware","thunk","GlobalStyles","createGlobalStyle","App","title","subtitle","description","setRooms","exact","path","to","reportWebVitals","onPerfEntry","Function","getCLS","getFID","getFCP","getLCP","getTTFB","initializeApp","apiKey","authDomain","projectId","storageBucket","messagingSenderId","appId","measurementId","ReactDOM","render","StrictMode"],"mappings":"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","file":"static/js/main.fe991679.chunk.js","sourcesContent":["const size = {\r\n mobileS: '320px',\r\n mobileM: '375px',\r\n mobileL: '425px',\r\n tablet: '768px',\r\n laptop: '1024px',\r\n laptopL: '1440px',\r\n desktop: '2560px',\r\n};\r\n\r\nexport const device = {\r\n mobileS: `(min-width: ${size.mobileS})`,\r\n mobileM: `(min-width: ${size.mobileM})`,\r\n mobileL: `(min-width: ${size.mobileL})`,\r\n tablet: `(min-width: ${size.tablet})`,\r\n laptop: `(min-width: ${size.laptop})`,\r\n laptopL: `(min-width: ${size.laptopL})`,\r\n desktop: `(min-width: ${size.desktop})`,\r\n desktopL: `(min-width: ${size.desktop})`,\r\n};\r\n\r\nexport function isMobile() {\r\n return window.innerWidth < 768;\r\n}\r\n","import { useEffect } from 'react';\r\n\r\n/**\r\n * useKeyPress\r\n * @param {string} key - the name of the key to respond to, compared against event.key\r\n * @param {function} action - the action to perform on key press\r\n */\r\nexport default function useKeyPress(key, action) {\r\n useEffect(() => {\r\n function onKeyup(e) {\r\n if (e.key === key) action();\r\n }\r\n window.addEventListener('keyup', onKeyup);\r\n return () => window.removeEventListener('keyup', onKeyup);\r\n }, []);\r\n}\r\n","export function isiOSDevice() {\r\n return (\r\n [\r\n 'iPad Simulator',\r\n 'iPhone Simulator',\r\n 'iPod Simulator',\r\n 'iPad',\r\n 'iPhone',\r\n 'iPod',\r\n ].includes(navigator.platform) ||\r\n // iPad on iOS 13 detection\r\n (navigator.userAgent.includes('Mac') && 'ontouchend' in document)\r\n );\r\n}\r\n","export const MAX_MESSAGE_LENGTH = 200;\r\n","import React, { useRef, useEffect } from 'react';\r\nimport styled from 'styled-components';\r\nimport { ArrowCircleUp } from '@styled-icons/fa-solid';\r\nimport { device } from '../constants/device-sizes';\r\nimport useKeyPress from './../hooks/useKeyPress';\r\nimport { useGoogleReCaptcha } from 'react-google-recaptcha-v3';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { isiOSDevice } from './../constants/deviceType';\r\nimport { CreativeCommonsNoncommercialEu } from '@styled-icons/entypo';\r\nimport { MAX_MESSAGE_LENGTH } from '../constants/message-constants';\r\n\r\nconst InputWrapper = styled.div`\r\n width: 100%;\r\n display: flex;\r\n justify-content: center;\r\n`;\r\n\r\nconst InputContainer = styled.div`\r\n border-radius: 2rem 2rem 0 0;\r\n filter: drop-shadow(0px 0px 4px var(--clr-shadow));\r\n background-color: var(--clr-prim);\r\n padding: 1rem 1rem 1rem 1rem;\r\n // margin: 0 auto;\r\n width: 100%;\r\n display: flex;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n`;\r\n\r\nconst InputTextBox = styled.input`\r\n margin: 0;\r\n width: 100%;\r\n filter: none;\r\n border-radius: 1rem;\r\n font-size: var(--fs-body);\r\n background-color: var(--clr-prim);\r\n color: var(--clr-sec);\r\n padding: 0.25em 0.75em;\r\n text-align: center;\r\n border: 1px solid var(--clr-shadow);\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n :focus {\r\n outline-width: 0px;\r\n box-shadow: 0 0 0 2pt #ccc;\r\n }\r\n`;\r\n\r\nconst InputContaineriOS = styled(InputContainer)`\r\n -webkit-appearance: none;\r\n position: absolute;\r\n bottom: var(--adj-height, 0px);\r\n z-index: var(--adj-z, -1);\r\n transform: var(--adj-scale, scale(1));\r\n transition: var(--adj-animation, none);\r\n filter: none;\r\n box-shadow: 0px 0px 8px var(--clr-shadow);\r\n padding-bottom: 3rem;\r\n`;\r\n\r\nconst SubmitButton = styled(ArrowCircleUp)`\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n margin: 0 0 0 1rem;\r\n border-radius: 1rem;\r\n width: 2rem;\r\n height: 2rem;\r\n background-color: var(--clr-prim);\r\n color: var(--clr-sec);\r\n border: 1px solid var(--clr-shadow);\r\n padding: 0.25rem 0.25rem;\r\n font-size: var(--fs-h3);\r\n :focus {\r\n outline-width: 0px;\r\n box-shadow: 0 0 0 2pt #ccc;\r\n }\r\n`;\r\n\r\nfunction convertRemToPixels(rem) {\r\n return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);\r\n}\r\n\r\nfunction RoomInputText(props) {\r\n const inputTextBox = useRef();\r\n const inputTextBoxiOS = useRef();\r\n const { executeRecaptcha } = useGoogleReCaptcha();\r\n\r\n useKeyPress('Enter', () => {\r\n if (isiOSDevice()) {\r\n onSubmitiOS();\r\n } else {\r\n onSubmit();\r\n }\r\n });\r\n\r\n function onSubmit() {\r\n submit(inputTextBox.current.value.trim());\r\n inputTextBox.current.value = '';\r\n }\r\n\r\n function onSubmitiOS() {\r\n submit(inputTextBoxiOS.current.value.trim());\r\n inputTextBoxiOS.current.value = '';\r\n inputTextBoxiOS.current.blur();\r\n }\r\n\r\n function submit(messageText) {\r\n if (messageText.length <= 0) {\r\n return;\r\n }\r\n let message = {\r\n id: uuidv4(),\r\n messageText: messageText,\r\n clicks: 0,\r\n size: 1.15,\r\n fontWeight: 900,\r\n };\r\n executeRecaptcha('submit').then((token) => {\r\n message.token = token;\r\n props.sendMessage(message);\r\n });\r\n\r\n props.displayMessage(message);\r\n }\r\n\r\n useEffect(() => {\r\n if (isiOSDevice()) {\r\n let maxPageHeight = window.innerHeight;\r\n inputTextBox.current.tabIndex = -1;\r\n document.documentElement.style.setProperty(\r\n '--adj-height',\r\n `${maxPageHeight}px`\r\n );\r\n\r\n inputTextBox.current.addEventListener('focus', (e) => {\r\n inputTextBoxiOS.current.focus();\r\n setTimeout(() => {\r\n document.documentElement.style.setProperty('--adj-animation', 'none');\r\n document.documentElement.style.setProperty('--adj-height', `0px`);\r\n document.documentElement.style.setProperty('--adj-z', '100');\r\n setTimeout(() => {\r\n document.documentElement.style.setProperty(\r\n '--adj-animation',\r\n 'all 0.2s cubic-bezier(.17,.59,.4,.77)'\r\n );\r\n document.documentElement.style.setProperty(\r\n '--adj-height',\r\n `${\r\n maxPageHeight -\r\n window.visualViewport.height -\r\n convertRemToPixels(2)\r\n }px`\r\n );\r\n }, 100);\r\n }, 5);\r\n });\r\n\r\n inputTextBoxiOS.current.addEventListener('blur', (e) => {\r\n document.documentElement.style.setProperty('--adj-z', '-1');\r\n document.documentElement.style.setProperty(\r\n '--adj-height',\r\n `${maxPageHeight}px`\r\n );\r\n document.documentElement.style.setProperty(\r\n '--adj-animation',\r\n 'all 0.01s ease'\r\n );\r\n setTimeout(() => {\r\n inputTextBox.current.value = inputTextBoxiOS.current.value;\r\n }, 10);\r\n });\r\n\r\n document.addEventListener('scroll', (e) => {\r\n if (document.activeElement === inputTextBoxiOS.current) {\r\n inputTextBoxiOS.current.blur();\r\n }\r\n });\r\n\r\n document.addEventListener('resize', (e) => {\r\n if (document.activeElement === inputTextBoxiOS.current) {\r\n inputTextBoxiOS.current.blur();\r\n }\r\n });\r\n }\r\n }, []);\r\n\r\n function setiOSComponent() {\r\n if (isiOSDevice()) {\r\n return (\r\n \r\n \r\n \r\n \r\n );\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n {setiOSComponent()}\r\n \r\n );\r\n}\r\n\r\nexport default RoomInputText;\r\n","// var retries = 0;\r\n// var totalTries = 0;\r\nexport function getPositionForNewDiv(newDiv, currentDivs, boundingRect) {\r\n var pos = partitionAlgorithm(\r\n newDiv,\r\n currentDivs,\r\n boundingRect,\r\n boundingRect,\r\n 0\r\n );\r\n\r\n let verified = verifyDivPos(\r\n new DOMRect(pos[0], pos[1], newDiv.width, newDiv.height),\r\n currentDivs,\r\n boundingRect,\r\n 0\r\n );\r\n //console.log(\"verified\", verified);\r\n // This retries / total tries stuff is for trying to figure out which cutoff in partitionAlgorithm\r\n // allows for the lowest chance of overlap\r\n //console.log(\"POS: \" + pos);\r\n //console.log(\"VERIFIED: \" + verified);\r\n //if (pos[0] !== verified[0]) {\r\n //retries++;\r\n //}\r\n // TODO: adjust from 0.01 cutoff in partition algoruithm\r\n //totalTries++;\r\n //console.log(\"RETRY PROP: \" + retries.toFixed() / totalTries);\r\n return verified;\r\n}\r\n\r\nfunction partitionAlgorithm(\r\n newDiv,\r\n currentDivs,\r\n boundingRect,\r\n outerBoundingRect,\r\n depth\r\n) {\r\n let rect1;\r\n let rect2;\r\n if (boundingRect.height > boundingRect.width) {\r\n let midPoint = boundingRect.top + boundingRect.height / 2;\r\n rect1 = new DOMRect(\r\n boundingRect.left,\r\n boundingRect.top,\r\n boundingRect.width,\r\n boundingRect.height / 2\r\n );\r\n rect2 = new DOMRect(\r\n boundingRect.left,\r\n midPoint,\r\n boundingRect.width,\r\n boundingRect.height / 2\r\n );\r\n } else {\r\n let midPoint = boundingRect.left + boundingRect.width / 2;\r\n rect1 = new DOMRect(\r\n boundingRect.left,\r\n boundingRect.top,\r\n boundingRect.width / 2,\r\n boundingRect.height\r\n );\r\n rect2 = new DOMRect(\r\n midPoint,\r\n boundingRect.top,\r\n boundingRect.width / 2,\r\n boundingRect.height\r\n );\r\n }\r\n\r\n let rect1Stack = [];\r\n let rect2Stack = [];\r\n let rect1TIS = 0;\r\n let rect2TIS = 0;\r\n for (var div of currentDivs) {\r\n if (doRectanglesIntersect(div, rect1)) {\r\n rect1Stack.push(div);\r\n rect1TIS += rectIntersectionArea(div, rect1);\r\n }\r\n if (doRectanglesIntersect(div, rect2)) {\r\n rect2Stack.push(div);\r\n rect2TIS += rectIntersectionArea(div, rect2);\r\n }\r\n }\r\n\r\n let rect1FilledProportion = rect1TIS / (rect1.width * rect1.height);\r\n let rect2FilledProportion = rect2TIS / (rect2.width * rect2.height);\r\n if (rect1FilledProportion === rect2FilledProportion) {\r\n if (Math.random() < 0.5) {\r\n return placeDivInCorner(newDiv, currentDivs, rect1, outerBoundingRect);\r\n } else {\r\n return placeDivInCorner(newDiv, currentDivs, rect2, outerBoundingRect);\r\n }\r\n }\r\n\r\n if (rect1FilledProportion < 0.01) {\r\n return placeDivInCorner(newDiv, rect1Stack, rect1, outerBoundingRect);\r\n } else if (rect2FilledProportion < 0.01 || depth >= 4) {\r\n return placeDivInCorner(newDiv, rect2Stack, rect2, outerBoundingRect);\r\n } else if (rect1FilledProportion < rect2FilledProportion) {\r\n return partitionAlgorithm(\r\n newDiv,\r\n rect1Stack,\r\n rect1,\r\n outerBoundingRect,\r\n ++depth\r\n );\r\n } else {\r\n return partitionAlgorithm(\r\n newDiv,\r\n rect2Stack,\r\n rect2,\r\n outerBoundingRect,\r\n ++depth\r\n );\r\n }\r\n}\r\n\r\nfunction placeDivInCorner(\r\n newDiv,\r\n currentDivs,\r\n boundingRect,\r\n outerBoundingRect\r\n) {\r\n let nearestLeft = boundingRect.left;\r\n let nearestRight = boundingRect.right;\r\n let nearestTop = boundingRect.top;\r\n let nearestBottom = boundingRect.bottom;\r\n let centerX = boundingRect.left + boundingRect.width / 2;\r\n let centerY = boundingRect.top + boundingRect.height / 2;\r\n\r\n for (var div of currentDivs) {\r\n if (div.right < centerX && div.right > nearestLeft) {\r\n nearestLeft = div.right;\r\n }\r\n if (div.left > centerX && div.left < nearestRight) {\r\n nearestRight = div.left;\r\n }\r\n if (div.bottom < centerY && div.bottom > nearestTop) {\r\n nearestTop = div.bottom;\r\n }\r\n if (div.top > centerY && div.top < nearestBottom) {\r\n nearestBottom = div.top;\r\n }\r\n }\r\n\r\n // Pick corner closest to edge\r\n let leftDFromEdge = nearestLeft - boundingRect.left;\r\n let rightDFromEdge = boundingRect.right - nearestRight;\r\n let topDFromEdge = nearestTop - boundingRect.top;\r\n let bottomDFromEdge = boundingRect.bottom - nearestBottom;\r\n let isOnLeftSide;\r\n let isOnTopSide;\r\n let newleft;\r\n let newtop;\r\n\r\n if (leftDFromEdge === rightDFromEdge) {\r\n isOnLeftSide = Math.random() < 0.5;\r\n } else {\r\n isOnLeftSide = leftDFromEdge < rightDFromEdge;\r\n }\r\n\r\n if (topDFromEdge === bottomDFromEdge) {\r\n isOnTopSide = Math.random() < 0.5;\r\n } else {\r\n isOnTopSide = topDFromEdge < bottomDFromEdge;\r\n }\r\n\r\n if (isOnLeftSide) {\r\n let outerRight = outerBoundingRect.left + outerBoundingRect.width;\r\n newleft =\r\n nearestLeft + newDiv.width < outerRight\r\n ? nearestLeft\r\n : outerRight - newDiv.width;\r\n } else {\r\n newleft = Math.max(nearestRight - newDiv.width, outerBoundingRect.left);\r\n }\r\n if (isOnTopSide) {\r\n let outerBottom = outerBoundingRect.top + outerBoundingRect.height;\r\n newtop =\r\n nearestTop + newDiv.height < outerBottom\r\n ? nearestTop\r\n : outerBottom - newDiv.height;\r\n } else {\r\n newtop = Math.max(nearestBottom - newDiv.height, outerBoundingRect.top);\r\n }\r\n\r\n return [newleft, newtop];\r\n}\r\n\r\nfunction verifyDivPos(newDiv, currentDivs, boundingRect, tryCount) {\r\n if (tryCount >= 30) {\r\n return [newDiv.left, newDiv.top];\r\n }\r\n\r\n for (var div of currentDivs) {\r\n if (doRectanglesIntersect(newDiv, div)) {\r\n let newleft =\r\n boundingRect.left + Math.random() * (boundingRect.width - newDiv.width);\r\n let newtop =\r\n boundingRect.top +\r\n Math.random() * (boundingRect.height - newDiv.height);\r\n console.log(\r\n 'Generating random pos ' +\r\n newleft +\r\n 'x ' +\r\n newtop +\r\n 'y after ' +\r\n tryCount +\r\n ' tries'\r\n );\r\n return verifyDivPos(\r\n new DOMRect(newleft, newtop, newDiv.width, newDiv.height),\r\n currentDivs,\r\n boundingRect,\r\n ++tryCount\r\n );\r\n }\r\n }\r\n\r\n // No intersections, good to go!\r\n return [newDiv.left, newDiv.top];\r\n}\r\n\r\nfunction rectIntersectionArea(rect1, rect2) {\r\n let x_overlap = Math.max(\r\n 0,\r\n Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left)\r\n );\r\n let y_overlap = Math.max(\r\n 0,\r\n Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top)\r\n );\r\n let overlapArea = x_overlap * y_overlap;\r\n return overlapArea;\r\n}\r\n\r\nexport function doRectanglesIntersect(a, b) {\r\n return (\r\n a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top\r\n );\r\n}\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport { device } from '../constants/device-sizes';\r\nimport { getPositionForNewDiv } from '../utils/geometry';\r\nimport $ from 'jquery';\r\n\r\nconst VentDiv = styled.div`\r\n position: absolute;\r\n font-size: var(--fs-body);\r\n max-width: 45%;\r\n text-align: center;\r\n word-wrap: break-word;\r\n overflow-wrap: break-word;\r\n overflow: hidden;\r\n @media ${device.tablet} {\r\n width: 25%;\r\n }\r\n transform: scale(1);\r\n transition: transform 0.2s linear;\r\n cursor: pointer;\r\n`;\r\n\r\nclass VentMessage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n this.curDiv = React.createRef();\r\n this.clicks = 0;\r\n this.onReceiveClick = this.onReceiveClick.bind(this);\r\n }\r\n\r\n getInset(rect) {\r\n let ratio;\r\n let curMsgCount = this.props.msgDivs.size;\r\n if (this.isMobile()) {\r\n ratio = 0.02;\r\n } else {\r\n let max = 0.35 - 0.2 * Math.random();\r\n ratio = Math.max(max - 0.035 * curMsgCount, 0.02);\r\n }\r\n let hInset = rect.width * ratio;\r\n let vInset = rect.height * ratio;\r\n return new DOMRect(\r\n rect.left + hInset,\r\n rect.top + vInset,\r\n rect.width - hInset * 2,\r\n rect.height - vInset * 2\r\n );\r\n }\r\n\r\n isMobile() {\r\n return window.innerWidth < 768;\r\n }\r\n\r\n getMsgDuration(msgText) {\r\n var displayTime = 10000 + (10000 * msgText.length) / 150;\r\n if (this.isMobile()) {\r\n let curMsgCount = this.props.msgDivs.size;\r\n let divCountMultiplier = 1.395 - 0.0556 * curMsgCount;\r\n displayTime *= divCountMultiplier;\r\n }\r\n displayTime = Math.max(displayTime, 2000);\r\n displayTime = Math.min(displayTime, 25000);\r\n return displayTime;\r\n }\r\n\r\n componentDidMount() {\r\n // console.log(\"Render\", this.props.msg.id, \"with divs\", this.props.msgDivs);\r\n // console.log(\"Render\", this.props.msgDivs);\r\n let msg = this.props.msg;\r\n var curDivs = Array.from(this.props.msgDivs.keys())\r\n .filter((key) => key !== this.props.msg.id)\r\n .map((key) =>\r\n this.props.msgDivs.get(key).curDiv.current.getBoundingClientRect()\r\n );\r\n\r\n this.curDiv.current.style.fontSize = msg.baseSize + 'px';\r\n //console.log(\"curdivs\", curDivs);\r\n //this.props.addRefToMap(this.curDiv, this.props.msg.id);\r\n let container = this.getInset(\r\n this.props.container.current.getBoundingClientRect()\r\n );\r\n\r\n let pos = getPositionForNewDiv(\r\n this.curDiv.current.getBoundingClientRect(),\r\n curDivs,\r\n container\r\n );\r\n this.curDiv.current.style.left = pos[0] + 'px';\r\n this.curDiv.current.style.top = pos[1] + 'px';\r\n\r\n $(this.curDiv.current)\r\n .hide()\r\n .fadeIn(1000)\r\n .fadeOut(this.getMsgDuration(msg.messageText), () => {\r\n //console.log(\"fading finished\", this.props.msg.id);\r\n this.props.onRemove(msg.id);\r\n });\r\n }\r\n\r\n componentDidUpdate(prevProps) {\r\n //console.log(\"component did update\", this.props.msg.id, prevProps.msg.clicks, this.props.msg.clicks);\r\n if (prevProps.msg.clicks < this.props.msg.clicks) {\r\n this.onReceiveClick(this.props.msg.clicks);\r\n }\r\n }\r\n\r\n onReceiveClick(clicks) {\r\n let result = 1.0 + 0.025 * Math.min(clicks, 10) + 0.025;\r\n this.curDiv.current.style.transform = 'scale(' + result + ')';\r\n setTimeout(() => {\r\n let finalSize = 1.0 + 0.025 * Math.min(clicks, 10);\r\n this.curDiv.current.style.transform = 'scale(' + finalSize + ')';\r\n }, 200);\r\n }\r\n\r\n render() {\r\n return (\r\n {\r\n this.props.onMessageClicked(this.props.msg);\r\n }}\r\n ref={this.curDiv}\r\n style={{\r\n top: this.props.msg.top,\r\n left: this.props.msg.left,\r\n color: this.props.msg.color,\r\n fontWeight: this.props.msg.fontWeight,\r\n }}>\r\n {this.props.msg.messageText}\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default VentMessage;\r\n","import React, { useRef, useEffect } from 'react';\r\nimport styled from 'styled-components';\r\nimport './messagesContainer.css';\r\nimport VentMessage from './ventMessage';\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n height: 100%;\r\n`;\r\n\r\nfunction MessagesContainer(vars) {\r\n const container = useRef();\r\n const refs = useRef(new Map());\r\n const BASE_FONT_SIZE =\r\n parseFloat(\r\n getComputedStyle(document.documentElement).getPropertyValue('--fs-body')\r\n ) * parseFloat(getComputedStyle(document.documentElement).fontSize);\r\n\r\n function addRefToMap(ref, id) {\r\n if (ref && !refs.current.has(id)) {\r\n refs.current.set(id, ref);\r\n }\r\n }\r\n\r\n function onRemove(id) {\r\n refs.current.delete(id);\r\n vars.onRemove(id);\r\n }\r\n\r\n // Never allow more than 40 messages to appear on screen at once\r\n useEffect(() => {\r\n if (vars.messages.size > 40) {\r\n onRemove(vars.messages.get(Array.from(vars.messages.keys())[0]).id);\r\n }\r\n }, [vars.messages]);\r\n\r\n function isMobile() {\r\n return window.innerWidth < 768;\r\n }\r\n\r\n // Setting this up weirdly since we can't get the amount of messages in room when a message comes in\r\n // For some reason, the messages variable is always an empty map within that set up useEffect()\r\n function getMsgFontSize(msg, curMsgCount) {\r\n if (msg.baseSize) {\r\n return msg.baseSize;\r\n }\r\n if (isMobile()) {\r\n var divCountMultiplier = 1.342 - curMsgCount * 0.043;\r\n var msgLengthMultiplier = 2.01 - 0.269 * Math.log(msg.messageText.length);\r\n } else {\r\n var divCountMultiplier = 1.357 - curMsgCount * 0.0366;\r\n var msgLengthMultiplier =\r\n 1.9855 - 0.239 * Math.log(msg.messageText.length);\r\n }\r\n\r\n let msgSizeMultiplier = msg.size !== undefined ? msg.size : 1.0;\r\n let finalSize = Math.max(\r\n divCountMultiplier *\r\n msgLengthMultiplier *\r\n msgSizeMultiplier *\r\n BASE_FONT_SIZE,\r\n BASE_FONT_SIZE * 0.5\r\n );\r\n msg.baseSize = finalSize;\r\n return finalSize;\r\n }\r\n\r\n return (\r\n \r\n {Array.from(vars.messages.values()).map((msg) => (\r\n {\r\n addRefToMap(ref, msg.id);\r\n }}\r\n onRemove={onRemove}\r\n onMessageClicked={vars.onMessageClicked}\r\n />\r\n ))}\r\n \r\n );\r\n}\r\n\r\nexport default MessagesContainer;\r\n","const SENT_MESSAGES_KEY = \"sent_messages\";\r\nconst DARK_MODE_KEY = \"dark_mode\";\r\nconst ONBOARDING_SHOWN_KEY = \"onboarding_shown\";\r\nconst ONBOARDING_INDEX = \"onboarding_index\";\r\nconst BLOCK_LIST_KEY = \"block_list\";\r\nconst MILLIS_PER_MIN = 1000 * 60;\r\nvar darkModeEnabled = readDarkModePreference();\r\nexport var inMemoryBlockList = getBlockList();\r\nenableDarkMode(darkModeEnabled);\r\n\r\nexport function getMessagesCache() {\r\n let storageItem = localStorage.getItem(SENT_MESSAGES_KEY);\r\n let sentMessages;\r\n if (storageItem === null) {\r\n sentMessages = new Map();\r\n } else {\r\n sentMessages = new Map(JSON.parse(storageItem));\r\n }\r\n\r\n return validateMessageCache(sentMessages);\r\n}\r\n\r\nfunction validateMessageCache(sentMessages) {\r\n for (const [key, value] of sentMessages.entries()) {\r\n if (Date.now() - value > 5 * MILLIS_PER_MIN) {\r\n sentMessages.delete(key);\r\n }\r\n }\r\n\r\n localStorage.setItem(SENT_MESSAGES_KEY, JSON.stringify([...sentMessages]));\r\n return sentMessages;\r\n}\r\n\r\nexport function cacheMessage(newMessage) {\r\n let sentMessages = getMessagesCache();\r\n sentMessages.set(newMessage, Date.now());\r\n localStorage.setItem(SENT_MESSAGES_KEY, JSON.stringify([...sentMessages]));\r\n}\r\n\r\n/* Dark Mode */\r\n\r\nfunction saveDarkModePreference(darkModeEnabled) {\r\n localStorage.setItem(DARK_MODE_KEY, JSON.stringify(darkModeEnabled));\r\n}\r\n\r\nexport function readDarkModePreference() {\r\n var darkModeEnabled = localStorage.getItem(DARK_MODE_KEY);\r\n if (\r\n darkModeEnabled === \"undefined\" ||\r\n darkModeEnabled === null ||\r\n darkModeEnabled == null\r\n ) {\r\n if (\r\n window.matchMedia &&\r\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches\r\n ) {\r\n darkModeEnabled = true;\r\n } else {\r\n darkModeEnabled = false;\r\n }\r\n saveDarkModePreference(darkModeEnabled);\r\n } else {\r\n darkModeEnabled = JSON.parse(darkModeEnabled);\r\n }\r\n return darkModeEnabled;\r\n}\r\n\r\nexport function hasSeenOnboarding() {\r\n var hasSeenOnboarding = localStorage.getItem(ONBOARDING_SHOWN_KEY);\r\n if (hasSeenOnboarding == null) {\r\n return false;\r\n }\r\n\r\n return hasSeenOnboarding;\r\n}\r\n\r\nexport function saveHasSeenOnboarding() {\r\n localStorage.setItem(ONBOARDING_SHOWN_KEY, true);\r\n}\r\n\r\nexport function toggleDarkMode() {\r\n darkModeEnabled = !darkModeEnabled;\r\n saveDarkModePreference(darkModeEnabled);\r\n enableDarkMode();\r\n return darkModeEnabled;\r\n}\r\n\r\nexport function setDarkMode(isDarkMode) {\r\n if (isDarkMode) {\r\n darkModeEnabled = true;\r\n } else {\r\n darkModeEnabled = false;\r\n }\r\n saveDarkModePreference(darkModeEnabled);\r\n enableDarkMode();\r\n}\r\n\r\nexport function getOnboardingIndex() {\r\n var onboardingIndex = localStorage.getItem(ONBOARDING_INDEX);\r\n if (onboardingIndex == null) {\r\n return 0;\r\n }\r\n\r\n return onboardingIndex;\r\n}\r\n\r\nexport function setOnboardingIndex(index) {\r\n localStorage.setItem(ONBOARDING_INDEX, index);\r\n}\r\n\r\nfunction enableDarkMode() {\r\n if (darkModeEnabled) {\r\n // Set screen to black\r\n document.documentElement.style.setProperty(\"--clr-prim\", \"#1e1e1e\");\r\n document.documentElement.style.setProperty(\"--clr-sec\", \"#e1e1e1\");\r\n document.documentElement.style.setProperty(\"--clr-tert\", \"#1e1e1e\");\r\n document.documentElement.style.setProperty(\"--clr-shadow\", \"#000\");\r\n document.documentElement.style.setProperty(\"--clr-bg\", \"#121212\");\r\n document.documentElement.style.setProperty(\"--clr-invert-bg\", \"#fdfdfd\");\r\n document.documentElement.style.setProperty(\"--clr-cached\", \"#999999\");\r\n //DARK_MODE_BUTTON.textContent = \"Light Mode\";\r\n } else {\r\n // Set screen to white\r\n document.documentElement.style.setProperty(\"--clr-prim\", \"#fff\");\r\n document.documentElement.style.setProperty(\"--clr-sec\", \"#000\");\r\n document.documentElement.style.setProperty(\"--clr-tert\", \"#ebedef\");\r\n document.documentElement.style.setProperty(\"--clr-shadow\", \"#dedede\");\r\n document.documentElement.style.setProperty(\"--clr-bg\", \"#fdfdfd\");\r\n document.documentElement.style.setProperty(\"--clr-invert-bg\", \"#121212\");\r\n document.documentElement.style.setProperty(\"--clr-cached\", \"#777777\");\r\n //DARK_MODE_BUTTON.textContent = \"Dark Mode\";\r\n }\r\n}\r\n\r\nexport function getBlockList() {\r\n let storageItem = localStorage.getItem(BLOCK_LIST_KEY);\r\n let blockList;\r\n if (storageItem === null) {\r\n blockList = new Set();\r\n } else {\r\n blockList = new Set(JSON.parse(storageItem));\r\n }\r\n\r\n return blockList;\r\n}\r\n\r\nexport function addToBlockList(newBlock) {\r\n let blockList = getBlockList();\r\n blockList.add(newBlock);\r\n inMemoryBlockList = blockList;\r\n localStorage.setItem(BLOCK_LIST_KEY, JSON.stringify([...blockList]));\r\n}\r\n\r\nexport function removeFromBlockList(block) {\r\n let blockList = getBlockList();\r\n blockList.delete(block);\r\n localStorage.setItem(BLOCK_LIST_KEY, JSON.stringify([...blockList]));\r\n}\r\n","export const API_URL = process.env.REACT_APP_API_URL\r\n ? process.env.REACT_APP_API_URL\r\n : \"https://ventscape.herokuapp.com/\";\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport { Users } from '@styled-icons/fa-solid/Users';\r\n\r\nconst Container = styled.div`\r\n display: flex;\r\n flex-direction: row;\r\n color: var(--clr-green);\r\n padding: 0.1rem 0.5rem;\r\n border-radius: 1rem;\r\n background: var(--clr-prim);\r\n margin-bottom: ${(props) => props.marginBottom};\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n`;\r\n\r\nconst Icon = styled(Users)`\r\n margin: auto 0.2rem auto 0;\r\n width: var(--fs-h3);\r\n height: var(--fs-h3);\r\n`;\r\n\r\nconst Count = styled.span`\r\n margin: 0;\r\n font-size: var(--fs-body);\r\n`;\r\n\r\nfunction OnlineCounter(props) {\r\n return (\r\n \r\n \r\n {props.count}\r\n \r\n );\r\n}\r\n\r\nexport default OnlineCounter;\r\n","import styled from 'styled-components';\r\nimport OnlineCounter from './onlineCounter';\r\nimport { Cog } from '@styled-icons/fa-solid/Cog';\r\nimport { device } from './../constants/device-sizes';\r\n\r\nconst Container = styled.div`\r\n position: absolute;\r\n justify-content: flex-end;\r\n right: 0px;\r\n top: 0px;\r\n padding: 1rem 0.25rem;\r\n justify-content: space-between;\r\n display: flex;\r\n flex-direction: row;\r\n padding: 0.6rem 0.25rem;\r\n @media ${device.mobileS} {\r\n padding: 0.75rem 0.25rem;\r\n }\r\n @media ${device.tablet} {\r\n padding: 1rem 1rem;\r\n }\r\n`;\r\n\r\nconst SettingsButton = styled(Cog)`\r\n cursor: pointer;\r\n transition: all 0.2s linear;\r\n margin-left: 0.25rem;\r\n width: 1.75rem;\r\n height: 2rem;\r\n :hover {\r\n transform: rotate(60deg);\r\n }\r\n @media ${device.tablet} {\r\n margin-left: 1rem;\r\n }\r\n`;\r\n\r\nconst RoomButtonsContainer = (props) => {\r\n function getOnlineCounter() {\r\n if (!props.isSolo) {\r\n return ;\r\n }\r\n }\r\n\r\n return (\r\n \r\n {getOnlineCounter()}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default RoomButtonsContainer;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport { device } from '../constants/device-sizes';\r\nimport RoomButtonsContainer from './roomButtonsContainer';\r\nconst MainContentWrapper = styled.div`\r\n width: 100%;\r\n`;\r\n\r\nconst MainContent = styled.div`\r\n width: 100%;\r\n margin: auto auto auto auto;\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n border-radius: 0 0 2rem 2rem;\r\n background: var(--clr-prim);\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n padding: var(--main-padding);\r\n`;\r\n\r\nconst VentScapeTitle = styled.h2`\r\n text-align: center;\r\n margin: auto auto;\r\n`;\r\n\r\nfunction RoomHeader(props) {\r\n return (\r\n \r\n \r\n VentScape\r\n \r\n \r\n \r\n );\r\n}\r\n\r\nexport default RoomHeader;\r\n","import styled from 'styled-components';\r\nimport { Times } from '@styled-icons/fa-solid/Times';\r\nimport { useRef } from 'react';\r\nimport {\r\n readDarkModePreference,\r\n toggleDarkMode,\r\n} from './../utils/localstorage';\r\n\r\nconst Container = styled.div`\r\n max-height: ${(props) => (props.isOpen ? '1000px' : '0px')};\r\n overflow: hidden;\r\n transition: background-color 0.2s linear;\r\n transition: max-height 0.2s linear;\r\n z-index: 10;\r\n border-radius: 0 0 2rem 2rem;\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n background-color: var(--clr-prim);\r\n position: absolute;\r\n top: 0px;\r\n width: 100%;\r\n margin: 0 auto;\r\n`;\r\n\r\nconst CloseButton = styled(Times)`\r\n cursor: pointer;\r\n position: absolute;\r\n width: 2.5rem;\r\n height: 2.5rem;\r\n top: 0px;\r\n right: 0px;\r\n margin: 1rem 1rem;\r\n font-size: 2rem;\r\n transition: all 0.2s linear;\r\n color: var(--clr-sec);\r\n :hover {\r\n color: red;\r\n }\r\n`;\r\n\r\nconst SettingsList = styled.ul`\r\n list-style-type: none;\r\n margin: 0 0;\r\n padding-top: 5rem;\r\n padding-bottom: 2.5rem;\r\n padding-left: 0;\r\n padding-right: 0;\r\n text-align: center;\r\n`;\r\n\r\nconst SettingsItem = styled.li`\r\n width: 50%;\r\n margin: auto auto 2rem;\r\n padding: 1rem;\r\n background-color: var(--clr-prim);\r\n border-radius: 2rem;\r\n color: var(--clr-sec);\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n a {\r\n text-decoration: none;\r\n color: inherit;\r\n display: block;\r\n margin: -1rem;\r\n padding: 1rem;\r\n }\r\n`;\r\n\r\nconst SettingsMenu = (props) => {\r\n const darkModeButton = useRef();\r\n function getDarkModePref() {\r\n return readDarkModePreference();\r\n }\r\n\r\n function menuToggleDarkMode() {\r\n let darkModeEnabled = toggleDarkMode();\r\n darkModeButton.current.innerText = darkModeEnabled\r\n ? 'Light Mode'\r\n : 'Dark Mode';\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n {getDarkModePref() ? 'Light Mode' : 'Dark Mode'}\r\n \r\n \r\n \r\n Leave feedback for VentScape on Reddit!\r\n \r\n \r\n \r\n \r\n Join the VentScape Discord\r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default SettingsMenu;\r\n","import React, { useState, useEffect, useRef } from 'react';\r\nimport styled from 'styled-components';\r\nimport RoomInputText from './roomInputText';\r\nimport { io } from 'socket.io-client';\r\nimport MessagesContainer from './messagesContainer';\r\nimport { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';\r\nimport './room.css';\r\nimport { getMessagesCache, cacheMessage } from './../utils/localstorage';\r\nimport { API_URL } from './../constants/string-constants';\r\nimport RoomHeader from './roomHeader';\r\nimport SettingsMenu from './settingsMenu';\r\nimport { v4 as uuidv4 } from 'uuid';\r\n\r\nconst RoomContainer = styled.div`\r\n display: flex;\r\n overflow: hidden;\r\n height: 100%;\r\n width: 100%;\r\n background-color: var(--clr-bg);\r\n justify-content: space-between;\r\n flex-direction: column;\r\n transition: background-color 0.2s linear;\r\n`;\r\n\r\nfunction Room(props) {\r\n const [messages, setMessages] = useState(new Map());\r\n const [onlineUsers, setOnlineUsers] = useState();\r\n const [settingsMenuOpen, openSettingsMenu] = useState(false);\r\n const socket = useRef();\r\n const selfPostedIdsSet = useRef(new Set());\r\n\r\n useEffect(() => {\r\n if (props.room.type === 'solo') {\r\n // Immediately return and do not connect for solo rooms\r\n return;\r\n }\r\n socket.current = io(API_URL);\r\n socket.current.on('joinRoom', () => {\r\n console.log('Joining', props.room.name);\r\n socket.current.emit('joinRoom', props.room.name);\r\n });\r\n socket.current.on('chat message', (msg) => {\r\n if (!selfPostedIdsSet.current.has(msg.id)) {\r\n console.log('Received message:', msg.messageText);\r\n\r\n if (document.visibilityState !== 'visible') {\r\n // TODO: Maybe add %PUBLIC_URL%\r\n document.getElementById('favicon').href = 'favicon-badged.ico';\r\n }\r\n\r\n if (msg.id === undefined) {\r\n // Prevents crash if some message somehow doesn't have an ID\r\n msg.id = uuidv4();\r\n }\r\n if (msg.clicks === undefined) {\r\n msg.clicks = 0;\r\n }\r\n setMessages((prev) => {\r\n let result = new Map(prev);\r\n result.set(msg.id, msg);\r\n console.log(result);\r\n return result;\r\n });\r\n } else {\r\n selfPostedIdsSet.current.delete(msg.id);\r\n }\r\n });\r\n\r\n socket.current.on('notification', (message) => {\r\n alert(message);\r\n });\r\n\r\n socket.current.on('click event', (msg) => {\r\n console.log('received click event');\r\n setMessages((prev) => {\r\n // Don't add a click to a message we haven't yet received\r\n if (!prev.has(msg.id)) {\r\n return prev;\r\n }\r\n console.log('prev', prev);\r\n let result = new Map(prev);\r\n let newMessage = { ...result.get(msg.id) };\r\n newMessage.clicks++;\r\n result.set(newMessage.id, newMessage);\r\n return result;\r\n });\r\n });\r\n\r\n socket.current.on('update', function (update) {\r\n if (update.type === 'onlineUsers') {\r\n setOnlineUsers(update.onlineUsers);\r\n }\r\n });\r\n\r\n document.addEventListener('visibilitychange', function (e) {\r\n if (document.visibilityState === 'visible') {\r\n document.getElementById('favicon').href = 'favicon.ico';\r\n }\r\n });\r\n\r\n return function cleanup() {\r\n socket.current.disconnect();\r\n };\r\n }, []);\r\n\r\n function onRemove(id) {\r\n setMessages((prev) => {\r\n let result = new Map(prev);\r\n result.delete(id);\r\n return result;\r\n });\r\n }\r\n\r\n function displayMessage(message) {\r\n setMessages((prev) => {\r\n let result = new Map(prev);\r\n result.set(message.id, message);\r\n return result;\r\n });\r\n }\r\n\r\n function sendMessage(message) {\r\n if (props.room.type === 'solo') {\r\n return;\r\n }\r\n\r\n let sentMessages = getMessagesCache();\r\n if (sentMessages.has(message.messageText)) {\r\n // Duplicate message\r\n return;\r\n }\r\n cacheMessage(message.messageText);\r\n selfPostedIdsSet.current.add(message.id);\r\n socket.current.emit('chat message', message);\r\n }\r\n\r\n function setSettingsMenuStateOpen() {\r\n console.log('open');\r\n openSettingsMenu(true);\r\n }\r\n\r\n function setSettingsMenuStateClosed() {\r\n openSettingsMenu(false);\r\n }\r\n\r\n function onMessageClicked(msg) {\r\n socket.current.emit('click event', msg);\r\n setMessages((prev) => {\r\n let result = new Map(prev);\r\n let newMessage = { ...result.get(msg.id) };\r\n newMessage.clicks++;\r\n result.set(newMessage.id, newMessage);\r\n return result;\r\n });\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n\r\nexport default Room;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport OnlineCounter from './onlineCounter';\r\nimport { device } from '../constants/device-sizes';\r\nimport { Link } from 'react-router-dom';\r\n\r\nconst RoomListItemWrapper = styled.div`\r\n width: 100%;\r\n display: flex;\r\n justify-content: center;\r\n`;\r\n\r\nconst RoomListItemContainer = styled.div`\r\n width: 100%;\r\n margin: 0.75rem 1rem;\r\n padding: 1rem 1rem;\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n border-radius: 1rem;\r\n background: var(--clr-prim);\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n\r\n @media ${device.laptop} {\r\n width: 40%;\r\n }\r\n`;\r\n\r\nconst Header = styled.div`\r\n display: flex;\r\n flex-direction: row;\r\n justify-content: space-between;\r\n`;\r\n\r\nconst Title = styled.h3`\r\n margin: auto;\r\n width: 100%;\r\n text-align: ${(props) => (props.type !== 'instructions' ? 'left' : 'center')};\r\n`;\r\n\r\nconst SubTitle = styled.p`\r\n margin: 0;\r\n margin-bottom: 1rem;\r\n font-size: var(--fs-body);\r\n white-space: pre-wrap;\r\n color: var(--clr-tert);\r\n width: 100%;\r\n text-align: ${(props) => (props.type !== 'instructions' ? 'left' : 'center')};\r\n`;\r\n\r\nconst Description = styled.p`\r\n margin: 0;\r\n margin-bottom: 1rem;\r\n white-space: pre-wrap;\r\n font-weight: var(--fw-light);\r\n font-size: var(--fs-body);\r\n`;\r\n\r\nconst ButtonContainer = styled.div`\r\n display: flex;\r\n justify-content: center;\r\n`;\r\n\r\nconst Button = styled.button`\r\n cursor: pointer;\r\n background-color: var(--clr-green);\r\n font-size: var(--fs-body-bold);\r\n color: #fff;\r\n border: none;\r\n padding: 0.5rem 3rem;\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n border-radius: 1rem;\r\n :focus {\r\n outline-width: 0px;\r\n box-shadow: 0 0 0 2pt #ccc;\r\n }\r\n`;\r\n\r\nfunction RoomListItem(props) {\r\n const {\r\n title,\r\n name,\r\n type,\r\n onlineUsers,\r\n subtitle,\r\n description,\r\n connectButton,\r\n } = props.room;\r\n\r\n function getOnlineCounter() {\r\n if (type !== 'instructions') {\r\n return ;\r\n }\r\n }\r\n\r\n function getConnectButton() {\r\n if (type !== 'instructions') {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n );\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n
\r\n {title}\r\n {getOnlineCounter()}\r\n
\r\n \r\n {subtitle}\r\n \r\n {description}\r\n {getConnectButton()}\r\n
\r\n
\r\n );\r\n}\r\n\r\nexport default RoomListItem;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport { device } from '../constants/device-sizes';\r\nconst MainContentWrapper = styled.div`\r\n width: 100%;\r\n`;\r\n\r\nconst MainContent = styled.div`\r\n width: 100%;\r\n margin: auto auto auto auto;\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n border-radius: 0 0 2rem 2rem;\r\n background: var(--clr-prim);\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n padding: var(--main-padding);\r\n`;\r\n\r\nconst VentScapeTitle = styled.h2`\r\n text-align: center;\r\n margin: auto auto;\r\n`;\r\n\r\nfunction Header() {\r\n return (\r\n \r\n \r\n VentScape\r\n \r\n \r\n );\r\n}\r\n\r\nexport default Header;\r\n","import React from 'react';\r\nimport RoomListItem from './roomListItem';\r\nimport Header from './header';\r\nimport styled from 'styled-components';\r\n\r\nconst Container = styled.div`\r\n padding-top: 0.75rem;\r\n padding-bottom: 0.75rem;\r\n`;\r\nfunction RoomsMenu(props) {\r\n return (\r\n \r\n
\r\n \r\n {props.rooms.map((room) => (\r\n \r\n ))}\r\n \r\n \r\n );\r\n}\r\n\r\nexport default RoomsMenu;\r\n","export const UPDATE_CONTAINER = 'UPDATE_CONTAINER';\r\n\r\nexport const updateContainer = (containerRect) => {\r\n return {\r\n type: UPDATE_CONTAINER,\r\n payload: { containerRect },\r\n };\r\n};\r\n","export const INCREMENT_ONBOARDING = \"INCREMENT_ONBOARDING\";\r\nexport const ASSIGNED_TOOLTIP_TO_MESSAGE = \"ASSIGNED_TOOOLTIP_TO_MESSAGE\";\r\n\r\nexport const incrementOnboarding = () => {\r\n return {\r\n type: INCREMENT_ONBOARDING,\r\n };\r\n};\r\n\r\nexport const assignedTooltipToMessage = () => {\r\n return {\r\n type: ASSIGNED_TOOLTIP_TO_MESSAGE,\r\n };\r\n};\r\n","import regex from \"emoji-regex\";\r\nimport { isMobile } from \"../constants/device-sizes\";\r\n\r\nimport { getPositionForNewDiv } from \"../utils/geometry\";\r\nimport { ASSIGNED_TOOLTIP_TO_MESSAGE } from \"./onboarding-actions\";\r\nexport const ADD_MESSAGE = \"ADD_MESSAGE\";\r\nexport const DELETE_MESSAGE = \"DELETE_MESSAGE\";\r\nexport const UPDATE_MESSAGE = \"UPDATE_MESSAGE\";\r\nexport const UPDATE_MESSAGES = \"UPDATE_MESSAGES\";\r\nexport const CACHE_MESSAGE = \"CACHE_MESSAGE\";\r\nexport const POP_MESSAGE = \"POP_MESSAGE\";\r\n\r\nexport const MESSAGE_STATUS_NEW = \"NEW\";\r\nexport const MESSAGE_STATUS_CACHED = \"CACHED\";\r\nexport const MESSAGE_STATUS_RANDOM = \"RANDOM\";\r\n\r\nconst emojiRegex = regex();\r\n\r\nexport const addMessage = (message) => {\r\n return { type: ADD_MESSAGE, payload: { message } };\r\n};\r\n\r\nexport const deleteMessage = (id) => {\r\n return { type: DELETE_MESSAGE, payload: { id } };\r\n};\r\n\r\nexport const updateMessage = (message) => {\r\n return {\r\n type: UPDATE_MESSAGE,\r\n payload: { message },\r\n };\r\n};\r\n\r\nexport const updateMessages = (messages) => {\r\n return {\r\n type: UPDATE_MESSAGES,\r\n payload: { messages },\r\n };\r\n};\r\n\r\nexport const cacheMessage = (message) => {\r\n return {\r\n type: CACHE_MESSAGE,\r\n payload: { message },\r\n };\r\n};\r\n\r\nexport const popMessage = () => {\r\n return {\r\n type: POP_MESSAGE,\r\n payload: {},\r\n };\r\n};\r\n\r\nexport const createMessage = (message) => {\r\n return (dispatch, getState) => {\r\n const messages = Object.values(getState().messages.byId);\r\n let messageCountMultiplier, messageLengthMultiplier;\r\n\r\n if (isMobile()) {\r\n messageCountMultiplier = 1.342 - messages.length * 0.043;\r\n messageLengthMultiplier =\r\n 2.01 - 0.269 * Math.log(message.messageText.length);\r\n } else {\r\n messageCountMultiplier = 1.357 - messages.length * 0.0366;\r\n messageLengthMultiplier =\r\n 1.9855 - 0.239 * Math.log(message.messageText.length);\r\n }\r\n\r\n const emojis = Array.from(\r\n message.messageText.matchAll(emojiRegex),\r\n (m) => m[0]\r\n );\r\n\r\n const singleEmojiMultiplier =\r\n emojis.length === 1 && message.messageText.length <= 2\r\n ? isMobile()\r\n ? 1.8\r\n : 1.3\r\n : 1;\r\n\r\n const adminSizeMultiplier = message.sizeMultiplier || 1;\r\n\r\n let BASE_FONT_SIZE =\r\n parseFloat(\r\n getComputedStyle(document.documentElement).getPropertyValue(\"--fs-body\")\r\n ) * parseFloat(getComputedStyle(document.documentElement).fontSize);\r\n\r\n if (isMobile()) {\r\n BASE_FONT_SIZE = Math.ceil(BASE_FONT_SIZE * 0.6);\r\n }\r\n\r\n var finalSize = Math.max(\r\n messageCountMultiplier *\r\n messageLengthMultiplier *\r\n singleEmojiMultiplier *\r\n adminSizeMultiplier *\r\n BASE_FONT_SIZE,\r\n BASE_FONT_SIZE * 0.5\r\n );\r\n\r\n if (!isFinite(finalSize)) {\r\n // This could happen if we somehow received a 0 length message, for example. Display the message with close to normal font size\r\n finalSize = BASE_FONT_SIZE * 0.6;\r\n }\r\n\r\n message.rect = new DOMRect(0, 0, 0, 0);\r\n message.fontSize = finalSize;\r\n message.triggerFadeOut = false;\r\n\r\n const onboarding = getState().onboarding;\r\n\r\n if (onboarding.needsMessage) {\r\n message.tooltipDisabled = false;\r\n message.onboardingIndex = onboarding.index;\r\n dispatch({ type: ASSIGNED_TOOLTIP_TO_MESSAGE });\r\n } else {\r\n message.tooltipDisabled = true;\r\n }\r\n\r\n dispatch(addMessage(message));\r\n };\r\n};\r\n\r\nexport const moveMessage = (id, width, height) => {\r\n return (dispatch, getState) => {\r\n const messages = Object.values(getState().messages.byId);\r\n const ui = Object.values(getState().ui);\r\n const { containerRect } = getState();\r\n\r\n const message = messages.find((msg) => msg.id === id);\r\n const initialRect = new DOMRect(0, 0, width, height);\r\n\r\n let max = 0.35 - 0.2 * Math.random();\r\n const ratio = Math.max(max - 0.035 * messages.length, 0.02);\r\n const leftInset = containerRect.width * ratio + Math.random() * 0.05;\r\n const rightInset = containerRect.width * ratio + Math.random() * 0.05;\r\n const topInset = containerRect.height * ratio + Math.random() * 0.05;\r\n const bottomInset = containerRect.height * ratio + Math.random() * 0.05;\r\n\r\n const boundingRect = new DOMRect(\r\n containerRect.left + leftInset,\r\n containerRect.top + topInset,\r\n containerRect.width - (leftInset + rightInset),\r\n containerRect.height - (topInset + bottomInset)\r\n );\r\n\r\n const existingMessages = messages\r\n .map((a) => a.rect)\r\n .filter((rect) => rect.height !== 0 && rect.width !== 0);\r\n\r\n const existingRects = existingMessages.concat(...ui);\r\n try {\r\n existingRects.push(\r\n document\r\n .getElementsByClassName(\"grecaptcha-badge\")[0]\r\n .getBoundingClientRect()\r\n );\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n\r\n const [newX, newY] = getPositionForNewDiv(\r\n initialRect,\r\n existingRects,\r\n boundingRect\r\n );\r\n\r\n message.rect = new DOMRect(newX, newY, width, height);\r\n\r\n const messageCountModifier = 1.395 - 0.0556 * messages.length;\r\n const messageTypeModifier =\r\n message.status === MESSAGE_STATUS_CACHED ? 0.6 : 1;\r\n let fadeOutDuration = 10000 + (10000 * message.messageText.length) / 150;\r\n\r\n fadeOutDuration *= messageCountModifier;\r\n fadeOutDuration *= messageTypeModifier;\r\n fadeOutDuration = Math.max(fadeOutDuration, 2000);\r\n fadeOutDuration = Math.min(fadeOutDuration, 25000);\r\n\r\n message.fadeOutDuration = fadeOutDuration;\r\n\r\n dispatch(updateMessage(message));\r\n };\r\n};\r\n\r\nexport const removeMessage = (id) => {\r\n return (dispatch, getState) => {\r\n const messages = Object.values(getState().messages.byId);\r\n const message = messages.find((msg) => msg.id === id);\r\n\r\n if (\r\n message != null &&\r\n message.status != null &&\r\n message.status === MESSAGE_STATUS_NEW\r\n ) {\r\n dispatch(cacheMessage(message));\r\n }\r\n\r\n dispatch(deleteMessage(id));\r\n };\r\n};\r\n\r\nexport const removeMessagesFromUserId = (userId) => {\r\n return (dispatch, getState) => {\r\n const allMessages = Object.values(getState().messages.byId);\r\n const filteredMessages = allMessages.filter((msg) => msg.userId === userId);\r\n\r\n for (const message of filteredMessages) {\r\n dispatch(deleteMessage(message.id));\r\n }\r\n };\r\n};\r\n\r\nexport const popCachedMessage = () => {\r\n return (dispatch, getState) => {\r\n const cachedMessages = getState().messages.cached;\r\n\r\n if (cachedMessages.length === 0) {\r\n return Promise.resolve(true);\r\n }\r\n\r\n const latestCached = cachedMessages.slice(-1)[0];\r\n\r\n const message = {\r\n messageText: latestCached.messageText,\r\n id: latestCached.id,\r\n status: MESSAGE_STATUS_CACHED,\r\n color: latestCached.color,\r\n sizeMultiplier: latestCached.sizeMultiplier,\r\n };\r\n\r\n dispatch(createMessage(message));\r\n dispatch(popMessage());\r\n return Promise.resolve(false);\r\n };\r\n};\r\n\r\nexport const fadeOutRandomMessages = () => {\r\n return (dispatch, getState) => {\r\n const messages = Object.values(getState().messages.byId);\r\n const randomMessages = messages\r\n .filter((message) => message.status === MESSAGE_STATUS_RANDOM)\r\n .map((message) => {\r\n message.triggerFadeOut = true;\r\n message.fadeOutDuration = 2000;\r\n return message;\r\n });\r\n dispatch(updateMessages(randomMessages));\r\n };\r\n};\r\n","import { useSelector } from \"react-redux\";\r\n\r\nimport React, { useState, useEffect } from \"react\";\r\nimport ReactTooltip from \"react-tooltip\";\r\nimport { setOnboardingIndex } from \"../utils/localstorage\";\r\n\r\nfunction useOnboardingTooltip(ref, index) {\r\n const [tooltipDisabled, setTooltipDisabled] = useState(true);\r\n const [hasShown, setHasShown] = useState(false);\r\n const onboardingIndex = useSelector((state) => state.onboarding.index);\r\n\r\n useEffect(() => {\r\n if (onboardingIndex === index) {\r\n // console.log(\r\n // \"INDEXES MATCH:\",\r\n // index,\r\n // \"HAS SHOWN:\",\r\n // hasShown,\r\n // \"REF:\",\r\n // ref.current\r\n // );\r\n setTimeout(() => {\r\n if (hasShown === false) {\r\n setTooltipDisabled(false);\r\n ReactTooltip.show(ref.current);\r\n setHasShown(true);\r\n }\r\n }, 1000);\r\n\r\n setTimeout(() => {\r\n ReactTooltip.hide(ref.current);\r\n setTooltipDisabled(true);\r\n }, 7500);\r\n } else {\r\n setTooltipDisabled(true);\r\n }\r\n }, [onboardingIndex]);\r\n\r\n return tooltipDisabled;\r\n}\r\n\r\nexport default useOnboardingTooltip;\r\n","import React, { useEffect, useRef, useState } from \"react\";\r\nimport { useLayoutEffect } from \"react\";\r\nimport { useDispatch, useSelector } from \"react-redux\";\r\nimport styled from \"styled-components\";\r\nimport { device } from \"../../constants/device-sizes\";\r\nimport {\r\n removeMessage,\r\n removeMessagesFromUserId,\r\n} from \"../../store/messages-actions\";\r\nimport {\r\n MESSAGE_STATUS_CACHED,\r\n moveMessage,\r\n} from \"../../store/messages-actions\";\r\nimport $ from \"jquery\";\r\nimport bez from \"bez/src/jquery.bez\";\r\nimport moment from \"moment\";\r\nimport ReactTooltip from \"react-tooltip\";\r\nimport useOnboardingTooltip from \"../../hooks/useOnboardingTooltip\";\r\nimport { addToBlockList } from \"../../utils/localstorage\";\r\nconst options = [\"one\", \"two\", \"three\"];\r\nconst defaultOption = options[0];\r\n\r\nbez($);\r\n\r\nconst Text = styled.p`\r\n color: ${(props) => {\r\n if (props.color) {\r\n return props.color;\r\n } else if (props.status === MESSAGE_STATUS_CACHED) {\r\n return \"var(--clr-cached)\";\r\n } else {\r\n return \"var(--clr-sec)\";\r\n }\r\n }};\r\n font-weight: ${(props) => (props.bold ? \"600\" : \"normal\")};\r\n text-align: center;\r\n margin: 0;\r\n line-height: ${(props) => 1.2 * props.fontSize + \"px\"};\r\n`;\r\n\r\nconst DateText = styled.p`\r\n color: ${(props) => {\r\n if (props.color) {\r\n return props.color;\r\n } else if (props.status === MESSAGE_STATUS_CACHED) {\r\n return \"var(--clr-cached)\";\r\n } else {\r\n return \"var(--clr-sec)\";\r\n }\r\n }};\r\n text-align: center;\r\n font-size: var(--fs-body-small);\r\n margin: 0;\r\n padding: 0;\r\n`;\r\n\r\nconst Container = styled.div`\r\n position: absolute;\r\n text-align: center;\r\n word-wrap: break-word;\r\n overflow-wrap: break-word;\r\n overflow: hidden;\r\n max-width: 45%;\r\n @media ${device.tablet} {\r\n max-width: 25%;\r\n }\r\n opacity: 0;\r\n will-change: transform, opacity;\r\n margin: 0;\r\n padding: 0.5rem;\r\n -webkit-user-select: none; /* Safari */\r\n -moz-user-select: none; /* Firefox */\r\n -ms-user-select: none; /* IE10+/Edge */\r\n user-select: none; /* Standard */\r\n`;\r\n\r\nconst BlockButton = styled.button`\r\n background-color: var(--clr-tert);\r\n color: var(--clr-sec);\r\n border: none;\r\n margin: 0.5rem 0 0 0;\r\n padding: 0.5rem 1rem;\r\n`;\r\n\r\nconst Message = (props) => {\r\n const dispatch = useDispatch();\r\n const [size, setSize] = useState({ width: 0, height: 0 });\r\n const [messageMoved, setMessageMoved] = useState(false);\r\n const [blockButtonVisible, setBlockButtonVisible] = useState(false);\r\n\r\n const messageRef = useRef();\r\n const tooltipDisabled = useOnboardingTooltip(\r\n messageRef,\r\n props.message.onboardingIndex\r\n );\r\n\r\n function onboardingMessage() {\r\n let index = props.message.onboardingIndex;\r\n if (index === 0) {\r\n return \"All messages are from real people\";\r\n } else if (index === 2) {\r\n return \"All messages fade away automatically after a few seconds\";\r\n } else if (index === 3) {\r\n return \"Each person's messages have their own unique color\";\r\n } else {\r\n return \"\";\r\n }\r\n }\r\n\r\n function onBlockClicked() {\r\n let blockedUserId = props.message.userId;\r\n console.log(\"Blocking user\", blockedUserId);\r\n\r\n // Add their userId to the block list\r\n addToBlockList(blockedUserId);\r\n\r\n // Remove all of their messages\r\n dispatch(removeMessagesFromUserId(blockedUserId));\r\n\r\n // Make block API request\r\n props.sendBlockedUserToServer(props.message);\r\n }\r\n\r\n const { width, height } = size;\r\n const {\r\n id,\r\n rect,\r\n fontSize,\r\n fadeOutDuration,\r\n messageText,\r\n status,\r\n color,\r\n bold,\r\n createdAt,\r\n } = props.message;\r\n\r\n useLayoutEffect(() => {\r\n if (messageRef) {\r\n setSize({\r\n width: messageRef.current.clientWidth,\r\n height: messageRef.current.clientHeight,\r\n });\r\n }\r\n }, [messageRef]);\r\n\r\n useEffect(() => {\r\n if (height === 0 || width === 0 || messageMoved) {\r\n return;\r\n }\r\n setMessageMoved(true);\r\n dispatch(moveMessage(id, width, height));\r\n }, [height, width, dispatch, id, messageMoved]);\r\n\r\n useEffect(() => {\r\n if (!fadeOutDuration) {\r\n return;\r\n }\r\n $(messageRef.current)\r\n .fadeTo(1000, 1)\r\n .fadeTo(fadeOutDuration, 0, $.bez([1, 0.75, 0.9, 0.8]), () => {\r\n dispatch(removeMessage(id));\r\n });\r\n }, [fadeOutDuration, dispatch, id]);\r\n\r\n function focusMessage() {\r\n $(messageRef.current).stop().fadeTo(750, 1);\r\n }\r\n\r\n function unFocusMessage() {\r\n $(messageRef.current)\r\n .stop()\r\n .fadeTo(\r\n messageRef.current.style.opacity * (fadeOutDuration / 2),\r\n 0,\r\n $.bez([1, 0.75, 0.9, 0.8]),\r\n () => {\r\n dispatch(removeMessage(id));\r\n }\r\n );\r\n }\r\n\r\n // console.log(\"Message with tooltipdisabled\", props.message);\r\n\r\n function onClickContainer() {\r\n if (props.message.userId !== \"self\") {\r\n setBlockButtonVisible(!blockButtonVisible);\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n {messageText}\r\n \r\n {status === MESSAGE_STATUS_CACHED && (\r\n {moment(createdAt).fromNow()}\r\n )}\r\n {blockButtonVisible && (\r\n Block this user\r\n )}\r\n \r\n );\r\n};\r\n\r\nfunction messagePropsAreEqual(prevMessage, nextMessage) {\r\n return prevMessage.message === nextMessage.message;\r\n}\r\n\r\nexport default React.memo(Message, messagePropsAreEqual);\r\n","import React, { useRef, useLayoutEffect, useEffect } from \"react\";\r\nimport { useState } from \"react\";\r\nimport { useDispatch, useSelector } from \"react-redux\";\r\nimport styled from \"styled-components\";\r\nimport { updateContainer } from \"../../store/container-actions\";\r\nimport Message from \"./Message\";\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n height: 100%;\r\n`;\r\n\r\nfunction MessagesContainer(props) {\r\n const dispatch = useDispatch();\r\n const containerRef = useRef();\r\n const [rect, setRect] = useState(new DOMRect(0, 0, 0, 0));\r\n\r\n useLayoutEffect(() => {\r\n if (containerRef) {\r\n setRect(containerRef.current.getBoundingClientRect());\r\n }\r\n }, [dispatch]);\r\n\r\n useEffect(() => {\r\n const handleResize = () => {\r\n let rect = containerRef.current.getBoundingClientRect();\r\n if (\r\n window.visualViewport &&\r\n window.innerHeight !== window.visualViewport.height\r\n ) {\r\n rect = new DOMRect(\r\n 0,\r\n window.visualViewport.offsetTop,\r\n rect.width,\r\n rect.height -\r\n (window.innerHeight - window.visualViewport.height) -\r\n window.visualViewport.offsetTop\r\n );\r\n }\r\n setRect(rect);\r\n };\r\n\r\n if (window.visualViewport) {\r\n window.visualViewport.addEventListener(\"resize\", handleResize);\r\n } else {\r\n window.addEventListener(\"resize\", handleResize);\r\n }\r\n\r\n return () => {\r\n return () => {\r\n if (window.visualViewport) {\r\n window.visualViewport.removeEventListener(\"resize\", handleResize);\r\n } else {\r\n window.removeEventListener(\"resize\", handleResize);\r\n }\r\n };\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n dispatch(updateContainer(rect));\r\n }, [dispatch, rect]);\r\n\r\n const messages = useSelector(\r\n (state) => Object.values(state.messages.byId),\r\n (prevState, nextState) => {\r\n return prevState.length === nextState.length;\r\n }\r\n );\r\n\r\n const onboardingIndex = useSelector((state) => state.onboarding.index);\r\n\r\n return (\r\n \r\n {messages.map((message, index) => (\r\n \r\n ))}\r\n \r\n );\r\n}\r\n\r\nexport default MessagesContainer;\r\n","import React from \"react\";\r\nimport styled from \"styled-components\";\r\nimport { isiOSDevice } from \"../../../constants/deviceType\";\r\nimport { MAX_MESSAGE_LENGTH } from \"../../../constants/message-constants\";\r\n\r\nconst Input = styled.input`\r\n margin: 0;\r\n margin-right: 0.25rem;\r\n flex-grow: 1;\r\n filter: none;\r\n border-radius: 1rem;\r\n font-size: var(--fs-body);\r\n background-color: var(--clr-tert);\r\n color: var(--clr-sec);\r\n padding: 0.3rem 0.75em;\r\n border: 0px;\r\n outline: none;\r\n line-height: 1;\r\n`;\r\n\r\nconst InputBox = React.forwardRef((props, ref) => {\r\n return (\r\n {\r\n props.onChange(event.target.value);\r\n }}\r\n onFocus={props.onFocus}\r\n onBlur={props.onBlur}\r\n />\r\n );\r\n});\r\n\r\nexport default InputBox;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\nimport { PaperPlane } from '@styled-icons/fa-solid';\r\n\r\nconst Button = styled(PaperPlane)`\r\n width: 2rem;\r\n height: 2rem;\r\n color: ${(props) => (props.enabled ? 'var(--clr-purple)' : '#aaa')};\r\n padding: 0.25rem 0.25rem;\r\n font-size: var(--fs-h3);\r\n :focus {\r\n outline-width: 0px;\r\n box-shadow: 0 0 0 2pt #ccc;\r\n }\r\n :hover {\r\n transform: rotate(-15deg);\r\n }\r\n transition: transform 0.2s linear;\r\n cursor: pointer;\r\n`;\r\n\r\nfunction SubmitButton(props) {\r\n return (\r\n {\r\n e.preventDefault();\r\n }}\r\n />\r\n );\r\n}\r\n\r\nexport default SubmitButton;\r\n","import React, { useRef, useState, useEffect } from 'react';\r\nimport styled from 'styled-components';\r\nimport { device } from '../../../constants/device-sizes';\r\nimport useKeyPress from '../../../hooks/useKeyPress';\r\nimport InputBox from './InputBox';\r\nimport SubmitButton from './SubmitButton';\r\n\r\nconst isInStandaloneMode = () =>\r\n 'standalone' in window.navigator && window.navigator.standalone;\r\n\r\nexport const Container = styled.div`\r\n padding: 0.75rem 0.5rem 0.75rem 0.5rem;\r\n padding-bottom: ${isInStandaloneMode() ? '1.75rem' : '0.75rem'};\r\n width: 100%;\r\n display: flex;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n background-color: var(--clr-bg);\r\n justify-content: space-between;\r\n`;\r\n\r\nfunction InputContainer(props) {\r\n const [inputText, setInputText] = useState('');\r\n const inputBox = useRef();\r\n const enabled = useRef(true);\r\n\r\n useEffect(() => {\r\n enabled.current = props.enabled;\r\n }, [props.enabled]);\r\n\r\n function submitMessage() {\r\n if (enabled.current) {\r\n props.sendMessage(inputBox.current.value);\r\n setInputText('');\r\n }\r\n }\r\n\r\n useKeyPress('Enter', () => {\r\n submitMessage();\r\n });\r\n\r\n return (\r\n \r\n {\r\n setInputText(text);\r\n }}\r\n />\r\n \r\n \r\n );\r\n}\r\n\r\nexport default InputContainer;\r\n","import React, { useState, useEffect } from 'react';\r\n\r\nfunction useWindowSize() {\r\n // Initialize state with undefined width/height so server and client renders match\r\n // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/\r\n const [windowSize, setWindowSize] = useState({\r\n width: undefined,\r\n height: undefined,\r\n });\r\n useEffect(() => {\r\n // Handler to call on window resize\r\n function handleResize() {\r\n // Set window width/height to state\r\n setWindowSize({\r\n windowWidth: window.innerWidth,\r\n windowHeight: window.innerHeight,\r\n visualViewportHeight: window.visualViewport\r\n ? window.visualViewport.height\r\n : window.innerHeight,\r\n });\r\n }\r\n // Add event listener\r\n if (window.visualViewport) {\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n } else {\r\n window.addEventListener('resize', handleResize);\r\n }\r\n // Call handler right away so state gets updated with initial window size\r\n handleResize();\r\n // Remove event listener on cleanup\r\n return () => {\r\n if (window.visualViewport) {\r\n window.visualViewport.removeEventListener('resize', handleResize);\r\n } else {\r\n window.removeEventListener('resize', handleResize);\r\n }\r\n };\r\n }, []); // Empty array ensures that effect is only run on mount\r\n return windowSize;\r\n}\r\n\r\nexport default useWindowSize;\r\n","import React, { useEffect, useRef, useState } from 'react';\r\nimport styled from 'styled-components';\r\nimport useWindowSize from '../../../hooks/useWindowSize';\r\nimport useKeyPress from '../../../hooks/useKeyPress';\r\nimport InputBox from './InputBox';\r\nimport SubmitButton from './SubmitButton';\r\nimport { Container as MockContainer } from './InputContainer';\r\n\r\nconst Container = styled(MockContainer)`\r\n -webkit-appearance: none;\r\n position: absolute;\r\n bottom: ${(props) => props.bottom};\r\n z-index: ${(props) => props.z_index};\r\n transition: ${(props) => props.transition};\r\n filter: none;\r\n padding-bottom: 3rem;\r\n transform: rotateZ(360deg);\r\n will-change: transform;\r\n`;\r\n\r\nfunction convertRemToPixels(rem) {\r\n return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);\r\n}\r\n\r\nfunction IOSInputContainer(props) {\r\n const [inputText, setInputText] = useState('');\r\n const [inputFocused, setInputFocused] = useState(false);\r\n const [inputActive, setInputActive] = useState(false);\r\n const [inputActiveSwitch, setInputActiveSwitch] = useState(false);\r\n const { windowHeight, visualViewportHeight } = useWindowSize();\r\n\r\n const iOSInputBox = useRef();\r\n\r\n const styles = useRef({\r\n transition: 'none',\r\n bottom: '9999px',\r\n z_index: '-1',\r\n });\r\n\r\n const prevVVH = useRef(0);\r\n\r\n const enabled = useRef(true);\r\n\r\n useEffect(() => {\r\n enabled.current = props.enabled;\r\n }, [props.enabled]);\r\n\r\n function submitMessage() {\r\n if (enabled.current) {\r\n props.sendMessage(iOSInputBox.current.value);\r\n setInputText('');\r\n }\r\n }\r\n\r\n useKeyPress('Enter', () => {\r\n submitMessage();\r\n });\r\n\r\n useEffect(() => {\r\n if (inputFocused && !inputActive) {\r\n styles.current.transition = 'none';\r\n styles.current.bottom = '0px';\r\n styles.current.z_index = '100';\r\n } else if (!inputFocused && inputActive) {\r\n styles.current.transition = 'all 0.01s ease';\r\n styles.current.bottom = '9999px';\r\n styles.current.z_index = '-1';\r\n setInputActive(false);\r\n }\r\n }, [inputFocused, inputActive]);\r\n\r\n useEffect(() => {\r\n function setRefs() {\r\n styles.current.transition = 'all 0.245s cubic-bezier(.21,.7,.38,.85)';\r\n styles.current.bottom = `${\r\n windowHeight - visualViewportHeight - convertRemToPixels(2.25)\r\n }px`;\r\n prevVVH.current = visualViewportHeight;\r\n }\r\n if (windowHeight !== visualViewportHeight && !inputActive && inputFocused) {\r\n setRefs();\r\n setInputActive(true);\r\n } else if (\r\n visualViewportHeight !== prevVVH.current &&\r\n inputActive &&\r\n inputFocused\r\n ) {\r\n setRefs();\r\n setInputActiveSwitch(true);\r\n }\r\n }, [windowHeight, visualViewportHeight, inputActive, inputFocused]);\r\n\r\n useEffect(() => {\r\n if (inputActiveSwitch) {\r\n setInputActiveSwitch(false);\r\n }\r\n }, [inputActiveSwitch]);\r\n\r\n useEffect(() => {\r\n const handleVisibilityChange = () => {\r\n if (document.visibilityState === 'hidden') {\r\n iOSInputBox.current.blur();\r\n }\r\n };\r\n document.addEventListener(\r\n 'visibilitychange',\r\n handleVisibilityChange,\r\n false\r\n );\r\n\r\n return () => {\r\n document.removeEventListener(\r\n 'visibilitychange',\r\n handleVisibilityChange,\r\n false\r\n );\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n const handleResize = () => {\r\n if (\r\n prevVVH.current !== window.visualViewport.height &&\r\n inputFocused &&\r\n inputActive\r\n ) {\r\n setTimeout(function () {\r\n window.scrollTo(0, 0);\r\n }, 50);\r\n }\r\n };\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n return () => {\r\n window.visualViewport.removeEventListener('resize', handleResize);\r\n };\r\n }, [inputActive, inputFocused]);\r\n\r\n return (\r\n \r\n \r\n {\r\n setInputText(text);\r\n }}\r\n onFocus={() => {\r\n iOSInputBox.current.focus();\r\n }}\r\n disabled={inputFocused}\r\n />\r\n \r\n \r\n \r\n {\r\n setInputText(text);\r\n }}\r\n onFocus={() => {\r\n setInputFocused(true);\r\n }}\r\n onBlur={() => {\r\n setInputFocused(false);\r\n }}\r\n />\r\n {\r\n submitMessage();\r\n }}\r\n enabled={props.enabled}\r\n />\r\n \r\n \r\n );\r\n}\r\n\r\nexport default IOSInputContainer;\r\n","import React, { useEffect, useRef } from \"react\";\r\nimport styled from \"styled-components\";\r\nimport { useGoogleReCaptcha } from \"react-google-recaptcha-v3\";\r\nimport { isiOSDevice as isIOSDevice } from \"../../../constants/deviceType\";\r\nimport InputContainer from \"./InputContainer\";\r\nimport IOSInputContainer from \"./IOSInputContainer\";\r\nimport ReactTooltip from \"react-tooltip\";\r\nimport useOnboardingTooltip from \"../../../hooks/useOnboardingTooltip\";\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n display: flex;\r\n justify-content: center;\r\n`;\r\n\r\nfunction InputBar(props) {\r\n const { executeRecaptcha } = useGoogleReCaptcha();\r\n\r\n const containerRef = useRef();\r\n const tooltipDisabled = useOnboardingTooltip(containerRef, 1);\r\n\r\n function sendMessage(messageText) {\r\n if (messageText.length <= 0) {\r\n return;\r\n }\r\n\r\n executeRecaptcha(\"submit\")\r\n .then((token) => {\r\n props.sendMessage(messageText, token);\r\n })\r\n .catch((err) => console.log(err));\r\n }\r\n\r\n return (\r\n \r\n \r\n {isIOSDevice() ? (\r\n \r\n ) : (\r\n \r\n )}\r\n \r\n \r\n );\r\n}\r\n\r\nexport default InputBar;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\n\r\nconst ContinueButton = styled.div`\r\n width: ${(props) => props.width};\r\n /* height: 48px; */\r\n border-radius: 32px;\r\n background-color: ${(props) => {\r\n if (props.isAffirmative) {\r\n return props.enabled ? 'var(--clr-purple)' : 'var(--clr-tert)';\r\n } else {\r\n return 'transparent';\r\n }\r\n }};\r\n align-items: center;\r\n justify-content: center;\r\n margin-left: 8px;\r\n margin-right: 8px;\r\n padding-left: 16px;\r\n padding-right: 16px;\r\n margin-top: 1rem;\r\n display: flex;\r\n`;\r\n\r\nconst ButtonText = styled.p`\r\n font-size: 24px;\r\n font-weight: ${(props) => (props.isAffirmative ? 300 : 'bold')};\r\n color: ${(props) => (props.isAffirmative ? '#fff' : 'var(--clr-purple)')};\r\n text-align: center;\r\n text-align-vertical: center;\r\n margin: 0;\r\n padding: 0;\r\n`;\r\n\r\nconst Indicator = styled.div`\r\n width: 48px;\r\n height: 48px;\r\n position: absolute;\r\n`;\r\n\r\n// Affirmative = affirmative button, a yes button, a continue button, etc\r\n// !Affirmative = negative button, a no button, a cancel button, etc\r\nconst ModalButton = ({\r\n isAffirmative = true,\r\n enabled = true,\r\n theme,\r\n width = 'auto',\r\n children,\r\n onClick,\r\n isLoading = false,\r\n}) => {\r\n function onPressInternal() {\r\n if (!isLoading) {\r\n onClick();\r\n }\r\n }\r\n return (\r\n \r\n {children}\r\n {isLoading ? : null}\r\n \r\n );\r\n};\r\n\r\nexport default ModalButton;\r\n","import React from 'react';\r\nimport styled from 'styled-components';\r\n\r\nconst Title = styled.h2`\r\n color: var(--clr-sec);\r\n font-size: var(--fs-h2);\r\n font-weight: bold;\r\n text-align: center;\r\n margin-bottom: 8px;\r\n`;\r\n\r\nconst TitleText = (props) => {\r\n return {props.children};\r\n};\r\n\r\nexport default TitleText;\r\n","import PhoneNumber from 'awesome-phonenumber';\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport styled from 'styled-components';\r\nimport Modal from 'styled-react-modal';\r\nimport ModalButton from './ModalButton';\r\nimport TitleText from './TitleText';\r\nimport { device } from './../../constants/device-sizes';\r\nimport Dropdown from 'react-dropdown';\r\nimport 'react-dropdown/style.css';\r\nimport { API_URL } from './../../constants/string-constants';\r\nimport ReactCodeInput from 'react-verification-code-input';\r\nimport {\r\n getAuth,\r\n RecaptchaVerifier,\r\n signInWithPhoneNumber,\r\n browserLocalPersistence,\r\n setPersistence,\r\n} from 'firebase/auth';\r\n\r\nconst ModalSC = Modal.styled`\r\n width: 100%;\r\n padding: 1rem;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n }\r\n`;\r\n\r\nconst ModalContent = styled.div`\r\n padding: 16px;\r\n background-color: var(--clr-bg);\r\n width: 100%;\r\n border-radius: 12px;\r\n shadow-opacity: 0.18;\r\n shadow-radius: 4px;\r\n shadow-color: #000;\r\n shadow-offset: 0px 4px;\r\n elevation: 10;\r\n`;\r\n\r\nconst Description = styled.p`\r\n color: ${(props) => props.theme.ALT_TEXT_COLOR};\r\n font-size: 20px;\r\n`;\r\n\r\nconst ButtonContainer = styled.div`\r\n display: flex;\r\n margin-top: 16px;\r\n justify-content: space-between;\r\n flex-direction: row;\r\n width: 100%;\r\n`;\r\n\r\nconst PhoneInputContainer = styled.div`\r\n width: 100%;\r\n display: flex;\r\n height: 100px;\r\n justify-content: center;\r\n flex-direction: row;\r\n align-items: center;\r\n`;\r\n\r\nconst PhoneInput = styled.input`\r\n padding-left: 16px;\r\n padding-right: 16px;\r\n padding-top: 8px;\r\n padding-bottom: 8px;\r\n width: 70%;\r\n max-width: 15rem;\r\n margin-left: 8px;\r\n font-size: 24px;\r\n border-radius: 32px;\r\n background-color: ${(props) => props.theme.MODAL_INPUT_BACKGROUND};\r\n color: ${(props) => props.theme.TEXT_COLOR};\r\n`;\r\n\r\nconst DropdownSC = styled(Dropdown)`\r\n width: 30px;\r\n`;\r\n\r\nconst Page = styled.div`\r\n width: 100%;\r\n height: 100%;\r\n`;\r\n\r\nconst ErrorText = styled.p`\r\n color: #d00;\r\n font-size: 14px;\r\n text-align: center;\r\n`;\r\n\r\nconst ModalButtonSC = styled.div`\r\n flex-grow: 1;\r\n`;\r\n\r\nconst CodeInput = styled(ReactCodeInput)`\r\n font-family: var(--ff-primary);\r\n`;\r\n\r\nconst PhoneSignUpModal = (props) => {\r\n const [phoneNumber, setPhoneNumber] = useState('');\r\n const [confirm, setConfirm] = useState(null);\r\n const [continueEnabled, setContinueEnabled] = useState(false);\r\n const [isLoading, setLoading] = useState(false);\r\n const [verificationCodeText, setVerificationCodeText] = useState('');\r\n const [errorText, setErrorText] = useState('');\r\n const [selectedCountry, setSelectedCountry] = useState('+1');\r\n const phoneInput = useRef(null);\r\n const codeField = useRef(null);\r\n const [curPage, setCurPage] = useState(0);\r\n const whiteListedPhoneNumber = useRef(false);\r\n const captchaRef = React.useRef(null);\r\n\r\n useEffect(() => {\r\n if (confirm == null) {\r\n setCurPage(0);\r\n setFocus(phoneInput, 500);\r\n } else {\r\n setCurPage(1);\r\n setFocus(codeField, 500);\r\n }\r\n }, [confirm]);\r\n\r\n useEffect(() => {\r\n if (confirm == null) {\r\n var initPn = selectedCountry + phoneNumber;\r\n var pn = PhoneNumber(initPn);\r\n // change isValid() to isPossible() if debugging so numbers like 6280000000 will work\r\n setContinueEnabled(pn.isValid());\r\n\r\n if (phoneNumber.length > 8 && phoneNumber.includes('+')) {\r\n checkPhoneWhitelist();\r\n }\r\n } else {\r\n setContinueEnabled(verificationCodeText.length === 6);\r\n if (verificationCodeText.length === 6) {\r\n verify();\r\n }\r\n }\r\n }, [phoneNumber, verificationCodeText, confirm]);\r\n\r\n async function checkPhoneWhitelist() {\r\n const token = await getAuth().currentUser.getIdToken();\r\n const result = await fetch(\r\n API_URL + 'phone-number?phone_number=' + phoneNumber.replace('+', '%2b'),\r\n {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: 'Bearer ' + token,\r\n },\r\n }\r\n );\r\n\r\n if (result.status === 200) {\r\n const responseJson = await result.json();\r\n whiteListedPhoneNumber.current = responseJson.phoneNumberFound;\r\n setContinueEnabled(responseJson.phoneNumberFound);\r\n } else {\r\n whiteListedPhoneNumber.current = false;\r\n setContinueEnabled(false);\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n setFocus(phoneInput, 100);\r\n if (props.visible) {\r\n // modalLargeToastRef.current.show({\r\n // type: 'info',\r\n // text1: 'Heads Up',\r\n // text2:\r\n // \"Due to moderation concerns, we're only accepting phone sign ups from a few English speaking countries for now. If you want to sign up but can't, email me gabe@ventscape.life\",\r\n // topOffset: 48,\r\n // height: 100,\r\n // visibilityTime: 30000,\r\n // });\r\n }\r\n }, [props.visible]);\r\n\r\n // This is the only way I can get auto focus to work. The auto focus prop just will not work and I don't know why\r\n function setFocus(viewRef, delay) {\r\n setTimeout(() => {\r\n if (viewRef.current) {\r\n viewRef.current.focus();\r\n }\r\n }, delay);\r\n }\r\n\r\n async function onPressContinue() {\r\n console.log(selectedCountry);\r\n if (continueEnabled && !isLoading) {\r\n setErrorText('');\r\n if (confirm == null) {\r\n setLoading(true);\r\n var fullPhoneNumber = whiteListedPhoneNumber.current\r\n ? phoneNumber\r\n : selectedCountry + phoneNumber;\r\n console.log('sending phone request ' + fullPhoneNumber);\r\n const auth = getAuth();\r\n const recaptcher = new RecaptchaVerifier(\r\n captchaRef.current,\r\n {\r\n size: 'invisible',\r\n callback: (response) => {\r\n // reCAPTCHA solved, allow signInWithPhoneNumber.\r\n //onSignInSubmit();\r\n },\r\n },\r\n auth\r\n );\r\n setPersistence(auth, browserLocalPersistence)\r\n .then(() => {\r\n console.log('sucess');\r\n return signInWithPhoneNumber(auth, fullPhoneNumber, recaptcher)\r\n .catch((error) => {\r\n console.log(error);\r\n setErrorText(\r\n \"Unknown error. Make sure you're connected to the internet\"\r\n );\r\n setLoading(false);\r\n })\r\n .then((confirmation) => {\r\n console.log('received confirmation', confirmation);\r\n setLoading(false);\r\n setConfirm(confirmation);\r\n });\r\n })\r\n .catch((error) => {\r\n // Handle Errors here.\r\n const errorCode = error.code;\r\n const errorMessage = error.message;\r\n console.log('error', error);\r\n });\r\n } else {\r\n verify();\r\n }\r\n }\r\n }\r\n\r\n async function verify() {\r\n //analytics().logEvent('phone_verification_attempt', {});\r\n setLoading(true);\r\n confirm\r\n .confirm(verificationCodeText)\r\n .catch((error) => {\r\n console.log(error.code, error.message, error);\r\n if (error.code === 'auth/invalid-verification-code') {\r\n setErrorText('Invalid code. Please try again.');\r\n } else {\r\n setErrorText(\r\n \"Unknown error. Make sure you're connected to the internet\"\r\n );\r\n }\r\n\r\n setLoading(false);\r\n })\r\n .then((result) => {\r\n // analytics().logSignUp({\r\n // method: 'phone',\r\n // });\r\n if (result !== undefined) {\r\n props.onSuccess();\r\n props.onClose();\r\n }\r\n setLoading(false);\r\n });\r\n }\r\n\r\n function onPressCancel() {\r\n if (confirm == null) {\r\n props.onClose();\r\n } else {\r\n setErrorText('');\r\n setConfirm(null);\r\n }\r\n }\r\n\r\n const countryPickerOptions = [\r\n { label: '🇬🇧 +44', value: '+44' },\r\n { label: '🇺🇸/🇨🇦 +1', value: '+1' },\r\n { label: '🇦🇺 +61', value: '+61' },\r\n { label: '🇳🇿 +64', value: '+64' },\r\n { label: '🇮🇪 +353', value: '+353' },\r\n ];\r\n\r\n function getCurrentPage() {\r\n if (curPage === 0) {\r\n return (\r\n \r\n Just one sec!\r\n \r\n We’ll send your message in a sec, we just need your phone number to\r\n verify that you’re a real person.{'\\n\\n'}Let’s keep VentScape spam\r\n free!\r\n \r\n \r\n {\r\n setSelectedCountry(option.value);\r\n }}\r\n />\r\n {\r\n setPhoneNumber(text.target.value);\r\n }}\r\n value={phoneNumber}\r\n keyboardType='phone-pad'\r\n autoCompleteType='tel'\r\n placeholder='555-555-5555'>\r\n \r\n \r\n );\r\n } else {\r\n return (\r\n \r\n Verify\r\n \r\n Just put in the 6 digit verification code we sent you and we’ll get\r\n your message sent right away\r\n \r\n\r\n \r\n \r\n \r\n \r\n );\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n {getCurrentPage()}\r\n {errorText}\r\n \r\n \r\n Cancel\r\n \r\n \r\n {isLoading ? '' : 'Continue'}\r\n \r\n \r\n
\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default PhoneSignUpModal;\r\n","import styled from \"styled-components\";\r\nimport { Times } from \"@styled-icons/fa-solid/Times\";\r\nimport { useRef } from \"react\";\r\nimport {\r\n readDarkModePreference,\r\n toggleDarkMode,\r\n} from \"./../../utils/localstorage\";\r\nimport { getAnalytics, logEvent } from \"firebase/analytics\";\r\nimport Modal from \"styled-react-modal\";\r\nimport { device } from \"./../../constants/device-sizes\";\r\nimport ModalButton from \"./ModalButton\";\r\n\r\nconst CloseButton = styled(Times)`\r\n cursor: pointer;\r\n position: absolute;\r\n width: 2.5rem;\r\n height: 2.5rem;\r\n top: 1rem;\r\n right: 1rem;\r\n margin: 1rem 1rem;\r\n font-size: 2rem;\r\n transition: all 0.2s linear;\r\n color: var(--clr-sec);\r\n :hover {\r\n color: red;\r\n }\r\n`;\r\n\r\nconst SettingsList = styled.ul`\r\n list-style-type: none;\r\n margin: 0 0;\r\n padding-top: 5rem;\r\n padding-bottom: 2.5rem;\r\n padding-left: 0;\r\n padding-right: 0;\r\n text-align: center;\r\n`;\r\n\r\nconst SettingsItem = styled.li`\r\n width: 50%;\r\n margin: auto auto 2rem;\r\n padding: 1rem;\r\n background-color: var(--clr-prim);\r\n border-radius: 2rem;\r\n color: var(--clr-sec);\r\n filter: drop-shadow(0px 4px 4px var(--clr-shadow));\r\n a {\r\n text-decoration: none;\r\n color: inherit;\r\n display: block;\r\n margin: -1rem;\r\n padding: 1rem;\r\n }\r\n`;\r\n\r\nconst ModalSC = Modal.styled`\r\n width: 100%;\r\n padding: 1rem;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n position: auto;\r\n top: auto;\r\n }\r\n top: 0px;\r\n position: absolute;\r\n`;\r\n\r\nconst ModalContent = styled.div`\r\n padding: 16px;\r\n background-color: var(--clr-bg);\r\n width: 100%;\r\n border-radius: 12px;\r\n shadow-opacity: 0.18;\r\n shadow-radius: 4px;\r\n shadow-color: #000;\r\n shadow-offset: 0px 4px;\r\n elevation: 10;\r\n a {\r\n text-decoration: none;\r\n color: inherit;\r\n display: block;\r\n margin: -1rem;\r\n padding: 1rem;\r\n }\r\n`;\r\n\r\nconst SettingsMenu = (props) => {\r\n const darkModeButton = useRef();\r\n function getDarkModePref() {\r\n return readDarkModePreference();\r\n }\r\n\r\n function menuToggleDarkMode() {\r\n let darkModeEnabled = toggleDarkMode();\r\n darkModeButton.current.innerText = darkModeEnabled\r\n ? \"Light Mode\"\r\n : \"Dark Mode\";\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"instructions_clicked\");\r\n props.openInstructions();\r\n }}>\r\n Instructions\r\n \r\n \r\n {getDarkModePref() ? \"Light Mode\" : \"Dark Mode\"}\r\n \r\n \r\n \r\n Leave feedback for VentScape on Reddit!\r\n \r\n \r\n {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"discord_clicked\", { referrer: \"settings\" });\r\n }}>\r\n \r\n Join the VentScape Discord\r\n \r\n \r\n \r\n \r\n Buy me a Coffee!\r\n \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default SettingsMenu;\r\n","import React, { useState, useEffect, useLayoutEffect } from 'react';\r\n\r\nfunction useComponentRect(ref) {\r\n const [componentRect, setComponentRect] = useState(new DOMRect(0, 0, 0, 0));\r\n\r\n useEffect(() => {\r\n function handleResize() {\r\n if (!ref || !ref.current) {\r\n return null;\r\n }\r\n setComponentRect(ref.current.getBoundingClientRect());\r\n }\r\n\r\n if (window.visualViewport) {\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n } else {\r\n window.addEventListener('resize', handleResize);\r\n }\r\n\r\n handleResize();\r\n\r\n return () => {\r\n if (window.visualViewport) {\r\n window.visualViewport.removeEventListener('resize', handleResize);\r\n } else {\r\n window.removeEventListener('resize', handleResize);\r\n }\r\n };\r\n }, []);\r\n\r\n useLayoutEffect(() => {\r\n if (ref && ref.current) {\r\n setComponentRect(ref.current.getBoundingClientRect());\r\n }\r\n }, []);\r\n\r\n return componentRect;\r\n}\r\n\r\nexport default useComponentRect;\r\n","export const UPDATE_UI = 'UPDATE_UI';\r\n\r\nexport const updateUI = (id, uiRect) => {\r\n return {\r\n type: UPDATE_UI,\r\n payload: { id, uiRect },\r\n };\r\n};\r\n","import React, { useRef } from \"react\";\r\nimport styled from \"styled-components\";\r\nimport { Cog } from \"@styled-icons/fa-solid/Cog\";\r\nimport { UndoAlt } from \"@styled-icons/fa-solid/UndoAlt\";\r\nimport { Recycle } from \"@styled-icons/fa-solid/Recycle\";\r\nimport { SignalWifiStatusbar4Bar as WifiOn } from \"@styled-icons/material/SignalWifiStatusbar4Bar\";\r\nimport { SignalWifiStatusbarConnectedNoInternet4 as WifiOff } from \"@styled-icons/material/SignalWifiStatusbarConnectedNoInternet4\";\r\nimport useComponentRect from \"../../hooks/useComponentRect\";\r\nimport { useEffect } from \"react\";\r\nimport { useDispatch } from \"react-redux\";\r\nimport { updateUI } from \"../../store/ui-actions\";\r\nimport ReactTooltip from \"react-tooltip\";\r\nimport useOnboardingTooltip from \"../../hooks/useOnboardingTooltip\";\r\n\r\nconst Wrapper = styled.div`\r\n position: absolute;\r\n width: 100%;\r\n display: flex;\r\n justify-content: center;\r\n top: 0.75rem;\r\n`;\r\n\r\nconst Container = styled.div`\r\n display: flex;\r\n position: absolute;\r\n right: 1rem;\r\n justify-content: space-between;\r\n`;\r\n\r\nconst ReplayButton = styled(UndoAlt)`\r\n cursor: pointer;\r\n transition: all 0.2s linear;\r\n width: 1.8rem;\r\n height: 2rem;\r\n @keyframes spin {\r\n from {\r\n transform: rotate(360deg);\r\n }\r\n to {\r\n transform: rotate(0deg);\r\n }\r\n }\r\n\r\n :hover {\r\n transform: scale(1.2);\r\n }\r\n animation: ${(props) =>\r\n props.replaying ? \"spin 2s linear infinite\" : \"none\"};\r\n\r\n transform: all 2s linear;\r\n outline: none;\r\n margin-left: 0.5rem;\r\n`;\r\n\r\nconst RecycleButton = styled(Recycle)`\r\n cursor: pointer;\r\n transition: all 0.2s linear;\r\n width: 1.8rem;\r\n height: 2rem;\r\n @keyframes spinn {\r\n from {\r\n transform: rotate(0deg);\r\n }\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n :hover {\r\n transform: scale(1.2);\r\n }\r\n animation: ${(props) =>\r\n props.recycling ? \"spinn 1.5s linear infinite\" : \"none\"};\r\n\r\n transform: all 2s linear;\r\n outline: none;\r\n margin-left: 0.5rem;\r\n`;\r\n\r\nconst SettingsButton = styled(Cog)`\r\n cursor: pointer;\r\n transition: all 0.2s linear;\r\n width: 1.8rem;\r\n height: 2rem;\r\n :hover {\r\n transform: rotate(60deg);\r\n }\r\n margin-left: 0.5rem;\r\n`;\r\n\r\nconst OnlineIndicatorContainer = styled.div`\r\n transition: all 0.2s linear;\r\n height: 2rem;\r\n width: 2rem;\r\n color: ${(props) => {\r\n if (props.connected >= 1) {\r\n return \"var(--clr-green)\";\r\n } else if (props.connected >= 0) {\r\n return \"orange\";\r\n } else {\r\n return \"red\";\r\n }\r\n }};\r\n`;\r\n\r\nfunction ButtonContainer(props) {\r\n const dispatch = useDispatch();\r\n\r\n const containerRef = useRef();\r\n const settingsRef = useRef();\r\n const tooltipDisabled = useOnboardingTooltip(settingsRef, 4);\r\n const componentRect = useComponentRect(containerRef);\r\n\r\n useEffect(() => {\r\n dispatch(updateUI(\"buttonContainer\", componentRect));\r\n }, [dispatch, componentRect]);\r\n\r\n return (\r\n \r\n \r\n = 1\r\n ? \"You are connected to VentScape!\"\r\n : \"Can't connect to VentScape\"\r\n }\r\n data-place=\"bottom\"\r\n connected={props.connected}\r\n >\r\n {props.connected >= 1 ? : }\r\n \r\n {/* */}\r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n\r\nexport default ButtonContainer;\r\n","import React, { useEffect } from 'react';\r\nimport { useSelector } from 'react-redux';\r\nimport styled from 'styled-components';\r\nimport { createMessage } from '../../../store/messages-actions';\r\nimport { useDispatch } from 'react-redux';\r\nimport { v4 as uuidv4 } from 'uuid';\r\n\r\nconst Container = styled.div`\r\n width: 100%;\r\n height: 100%;\r\n`;\r\n\r\nfunction inset(containerRect) {\r\n const hInset = containerRect.width * 0.01;\r\n const vInset = containerRect.height * 0.01;\r\n\r\n return new DOMRect(\r\n containerRect.left + hInset,\r\n containerRect.top + vInset,\r\n containerRect.width - hInset * 2,\r\n containerRect.height - vInset * 2\r\n );\r\n}\r\n\r\nfunction HighlightedComponents() {\r\n const messages = useSelector(\r\n (state) => Object.values(state.messages.byId),\r\n (prevState, nextState) => {\r\n return false;\r\n }\r\n );\r\n const ui = useSelector(\r\n (state) => Object.values(state.ui),\r\n (prevState, nextState) => {\r\n return false;\r\n }\r\n );\r\n const containerRect = inset(\r\n useSelector(\r\n (state) => state.containerRect,\r\n (prevState, nextState) => {\r\n return false;\r\n }\r\n )\r\n );\r\n\r\n return (\r\n \r\n {messages.map((message) => (\r\n \r\n ))}\r\n {ui.map((rect) => (\r\n \r\n ))}\r\n \r\n \r\n );\r\n}\r\n\r\nexport default HighlightedComponents;\r\n","import React, { useEffect } from 'react';\r\nimport { useDispatch } from 'react-redux';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { createMessage } from '../../../store/messages-actions';\r\n\r\nfunction DisplayRandomMessages() {\r\n const dispatch = useDispatch();\r\n useEffect(() => {\r\n function displayRandomMessage() {\r\n const message = {\r\n messageText: 'Chad '.repeat(Math.floor(1 + Math.random() * 9)),\r\n id: uuidv4(),\r\n };\r\n dispatch(createMessage(message));\r\n setTimeout(displayRandomMessage, 2000);\r\n }\r\n displayRandomMessage();\r\n }, []);\r\n\r\n return ;\r\n}\r\n\r\nexport default DisplayRandomMessages;\r\n","import { getAnalytics, logEvent } from \"firebase/analytics\";\r\nimport React from \"react\";\r\nimport \"react-dropdown/style.css\";\r\nimport styled from \"styled-components\";\r\nimport Modal from \"styled-react-modal\";\r\nimport { device } from \"./../../constants/device-sizes\";\r\nimport ModalButton from \"./ModalButton\";\r\nimport TitleText from \"./TitleText\";\r\n\r\nconst ModalSC = Modal.styled`\r\n width: 100%;\r\n padding: 1rem;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n position: auto;\r\n top: auto;\r\n }\r\n top: 0px;\r\n position: absolute;\r\n`;\r\n\r\nconst ModalContent = styled.div`\r\n padding: 16px;\r\n background-color: var(--clr-bg);\r\n width: 100%;\r\n border-radius: 12px;\r\n shadow-opacity: 0.18;\r\n shadow-radius: 4px;\r\n shadow-color: #000;\r\n shadow-offset: 0px 4px;\r\n elevation: 10;\r\n a {\r\n text-decoration: none;\r\n color: inherit;\r\n display: block;\r\n margin: -1rem;\r\n padding: 1rem;\r\n }\r\n`;\r\n\r\nconst Description = styled.p`\r\n color: var(--clr-sec);\r\n font-size: 1rem;\r\n margin: 0;\r\n @media ${device.tablet} {\r\n font-size: 1.2rem;\r\n }\r\n`;\r\n\r\nconst ButtonContainer = styled.div`\r\n display: flex;\r\n margin-top: 16px;\r\n\r\n align-items: center;\r\n flex-direction: column;\r\n @media ${device.tablet} {\r\n flex-direction: row;\r\n justify-content: space-between;\r\n }\r\n width: 100%;\r\n`;\r\n\r\nconst ModalButtonSC = styled.div`\r\n cursor: pointer;\r\n flex-grow: 1;\r\n width: 100%;\r\n margin-top: 1rem;\r\n margin-bottom: 1rem;\r\n`;\r\n\r\nconst ReachOutModal = (props) => {\r\n function onPressContinue() {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"reach_out_modal_closed\");\r\n props.onClose();\r\n }\r\n\r\n return (\r\n \r\n \r\n Hey there!\r\n\r\n \r\n This is Gabe, creator of VentScape. I'm reaching out to active users\r\n of the site and would love to learn more about what you like/dislike\r\n about the site and what features you'd like to see added in. If that\r\n sounds good, please message me on Discord or email me at\r\n gabe@ventscape.life. Thank you so much!\r\n \r\n \r\n {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"discord_clicked\", { referrer: \"reach_out\" });\r\n }}\r\n >\r\n \r\n Join the VentScape Discord\r\n \r\n \r\n \r\n Back to VentScape\r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default ReachOutModal;\r\n","import { getAnalytics, logEvent } from 'firebase/analytics';\r\nimport React from 'react';\r\nimport 'react-dropdown/style.css';\r\nimport styled from 'styled-components';\r\nimport Modal from 'styled-react-modal';\r\nimport { saveHasSeenOnboarding } from '../../utils/localstorage';\r\nimport { device } from './../../constants/device-sizes';\r\nimport ModalButton from './ModalButton';\r\nimport TitleText from './TitleText';\r\n\r\nconst ModalSC = Modal.styled`\r\n width: 100%;\r\n padding: 1rem;\r\n @media ${device.tablet} {\r\n width: 50%;\r\n position: auto;\r\n top: auto;\r\n }\r\n top: 0px;\r\n position: absolute;\r\n`;\r\n\r\nconst ModalContent = styled.div`\r\n padding: 16px;\r\n background-color: var(--clr-bg);\r\n width: 100%;\r\n border-radius: 12px;\r\n shadow-opacity: 0.18;\r\n shadow-radius: 4px;\r\n shadow-color: #000;\r\n shadow-offset: 0px 4px;\r\n elevation: 10;\r\n a {\r\n text-decoration: none;\r\n color: inherit;\r\n display: block;\r\n margin: -1rem;\r\n padding: 1rem;\r\n }\r\n`;\r\n\r\nconst SubTitle = styled.p`\r\n text-align: center;\r\n color: var(--clr-sec);\r\n font-size: 1.2rem;\r\n margin-bottom: 0.5rem;\r\n`;\r\n\r\nconst Description = styled.p`\r\n color: var(--clr-sec);\r\n font-size: 1rem;\r\n margin: 0;\r\n @media ${device.tablet} {\r\n font-size: 1.2rem;\r\n }\r\n`;\r\n\r\nconst ButtonContainer = styled.div`\r\n display: flex;\r\n justify-content: center;\r\n flex-direction: row;\r\n width: 100%;\r\n`;\r\n\r\nconst ModalButtonSC = styled.div`\r\n cursor: pointer;\r\n flex-grow: 1;\r\n`;\r\n\r\nconst OnboardingModal = (props) => {\r\n function onPressContinue() {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, 'onboarding_modal_closed');\r\n saveHasSeenOnboarding();\r\n props.onClose();\r\n }\r\n\r\n return (\r\n \r\n \r\n Welcome to VentScape\r\n \r\n Vent, chat, banter and see others doing the same in real-time\r\n \r\n \r\n • When you send a message, everyone on VentScape will see the message\r\n appear in real-time\r\n \r\n \r\n • All messages disappear automatically after ~10 seconds\r\n \r\n • Everyone is 100% anonymous\r\n \r\n • Use the buttons in the top right to replay old messages, replay\r\n newly missed messages, and access settings\r\n \r\n Have fun, and be (mostly) civil please!\r\n \r\n \r\n Let's go!\r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default OnboardingModal;\r\n","import { disableBodyScroll } from \"body-scroll-lock\";\r\nimport {\r\n getAuth,\r\n signInAnonymously,\r\n browserLocalPersistence,\r\n setPersistence,\r\n onAuthStateChanged,\r\n} from \"firebase/auth\";\r\nimport React, { useEffect, useRef, useState } from \"react\";\r\nimport { GoogleReCaptchaProvider } from \"react-google-recaptcha-v3\";\r\nimport { v4 as uuidv4 } from \"uuid\";\r\nimport { io } from \"socket.io-client\";\r\nimport styled from \"styled-components\";\r\nimport MessagesContainer from \"./MessagesContainer\";\r\nimport { API_URL } from \"../../constants/string-constants\";\r\nimport InputBar from \"./input/InputBar\";\r\nimport PhoneSignUpModal from \"./PhoneSignUpModal\";\r\nimport {\r\n createMessage,\r\n MESSAGE_STATUS_CACHED,\r\n MESSAGE_STATUS_NEW,\r\n} from \"../../store/messages-actions\";\r\nimport { useDispatch, useSelector } from \"react-redux\";\r\nimport SettingsMenu from \"./SettingsMenu\";\r\nimport ButtonContainer from \"./ButtonContainer\";\r\nimport HighlightedComponents from \"./debug/HighlightedComponents\";\r\nimport DisplayRandomMessages from \"./debug/DisplayRandomMessages\";\r\nimport { getAnalytics, logEvent } from \"firebase/analytics\";\r\nimport ReachOutModal from \"./ReachOutModal\";\r\nimport OnboardingModal from \"./OnboardingModal\";\r\nimport {\r\n hasSeenOnboarding,\r\n inMemoryBlockList,\r\n setOnboardingIndex,\r\n} from \"../../utils/localstorage\";\r\nimport { ToastContainer, toast } from \"react-toastify\";\r\nimport \"react-toastify/dist/ReactToastify.css\";\r\nimport useOnboardingTooltip from \"../../hooks/useOnboardingTooltip\";\r\nimport { INCREMENT_ONBOARDING } from \"../../store/onboarding-actions\";\r\n\r\nconst RoomContainer = styled.div`\r\n display: flex;\r\n overflow: hidden;\r\n height: 100%;\r\n width: 100%;\r\n background-color: var(--clr-bg);\r\n justify-content: space-between;\r\n flex-direction: column;\r\n transition: background-color 0.2s linear;\r\n`;\r\n\r\nfunction RoomV2(props) {\r\n const [modalIsOpen, setModalIsOpen] = useState(false);\r\n const [reachOutModalOpen, setReachOutModalOpen] = useState(false);\r\n const [onboardingModalOpen, setOnboardingModalOpen] = useState(false);\r\n const [settingsMenuIsOpen, setSettingsMenuIsOpen] = useState(false);\r\n const dispatch = useDispatch();\r\n\r\n const roomRef = useRef();\r\n const hasAlreadySignedIn = useRef(false);\r\n const socket = useRef(null);\r\n const messageQueue = useRef([]);\r\n const historicalMessages = useRef([]);\r\n const [connected, setConnected] = useState(-1);\r\n const [sendEnabled, setSendEnabled] = useState(true);\r\n const [replaying, setReplaying] = useState(false);\r\n const [recycling, setRecycling] = useState(false);\r\n const messagesSentCount = useRef(0);\r\n\r\n const onboardingInfo = useSelector((state) => state.onboarding);\r\n\r\n disableBodyScroll(roomRef.current);\r\n\r\n document.addEventListener(\"visibilitychange\", function (e) {\r\n if (document.visibilityState === \"visible\") {\r\n document.getElementById(\"favicon\").href = \"favicon.ico\";\r\n displayQueueMessage([...messageQueue.current], 2000);\r\n messageQueue.current = [];\r\n }\r\n });\r\n\r\n function displayQueueMessage(curQueue, interval) {\r\n if (curQueue.length === 0) {\r\n setReplaying(false);\r\n setRecycling(false);\r\n return;\r\n }\r\n\r\n const message = curQueue.shift();\r\n let blockList = inMemoryBlockList;\r\n if (blockList.has(message.userId)) {\r\n displayQueueMessage(curQueue, interval);\r\n return;\r\n }\r\n message.status = MESSAGE_STATUS_CACHED;\r\n dispatch(createMessage(message));\r\n setTimeout(function () {\r\n displayQueueMessage(curQueue, interval);\r\n }, interval);\r\n }\r\n\r\n async function registerUser(token) {\r\n console.log(\"Registering \" + token.substring(0, 10));\r\n try {\r\n const response = await fetch(API_URL + \"users\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: \"Bearer \" + token,\r\n },\r\n body: JSON.stringify({\r\n push_notification_token: null,\r\n }),\r\n });\r\n console.log(\"user registered\", await response.json());\r\n } catch (err) {\r\n console.log(\"Error registering user\", err);\r\n }\r\n }\r\n\r\n async function sendBlockedUserToServer(message) {\r\n const token = await getAuth().currentUser.getIdToken();\r\n console.log(\"blocking \" + token.substring(0, 10));\r\n let strippedMessage = {\r\n id: message.id,\r\n userId: message.userId,\r\n messageText: message.messageText,\r\n createdAt: message.createdAt,\r\n };\r\n try {\r\n const response = await fetch(API_URL + \"block\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: \"Bearer \" + token,\r\n },\r\n body: JSON.stringify({\r\n message: strippedMessage,\r\n }),\r\n });\r\n console.log(\"user registered\", await response.json());\r\n } catch (err) {\r\n console.log(\"Error registering user\", err);\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n const auth = getAuth();\r\n if (hasAlreadySignedIn.current === false) {\r\n onAuthStateChanged(auth, (user) => {\r\n console.log(\"cur user changed\");\r\n if (user == null) {\r\n signInAnonymously(auth)\r\n .then(async (result) => {\r\n // Signed in..\r\n registerUserAndConnectToSocket(result.user);\r\n })\r\n .catch((error) => {\r\n const errorCode = error.code;\r\n const errorMessage = error.message;\r\n // ...\r\n });\r\n } else {\r\n registerUserAndConnectToSocket(user);\r\n }\r\n });\r\n }\r\n\r\n function emit() {\r\n if (onboardingInfo.needsMessage === false) {\r\n setOnboardingIndex(onboardingInfo.index + 1);\r\n dispatch({ type: INCREMENT_ONBOARDING });\r\n } else {\r\n console.log(\"NOT EMITTING, NEEDS MESSAGE\");\r\n }\r\n }\r\n\r\n let interval = setInterval(() => {\r\n emit();\r\n }, 8000);\r\n\r\n setTimeout(() => {\r\n clearInterval(interval);\r\n }, 60000);\r\n }, []);\r\n\r\n async function registerUserAndConnectToSocket(user) {\r\n if (hasAlreadySignedIn.current === false) {\r\n hasAlreadySignedIn.current = true;\r\n const token = await user.getIdToken();\r\n console.log(\"signed in\");\r\n await registerUser(token);\r\n connectToSocket(token, user);\r\n }\r\n }\r\n\r\n function addHistoricalMessage(message) {\r\n historicalMessages.current.push(message);\r\n while (historicalMessages.current.length > 10) {\r\n historicalMessages.current.shift();\r\n }\r\n }\r\n\r\n function connectToSocket(token, user) {\r\n var reconnect = false;\r\n if (socket.current != null) {\r\n socket.current.disconnect();\r\n reconnect = true;\r\n }\r\n socket.current = io(API_URL, {\r\n auth: {\r\n token: \"Bearer \" + token,\r\n },\r\n });\r\n console.log(\"Connecting to socket\", API_URL);\r\n\r\n socket.current.on(\"chat message\", (message) => {\r\n let blockList = inMemoryBlockList;\r\n if (blockList.has(message.userId)) {\r\n return;\r\n }\r\n\r\n message.status = message.status || MESSAGE_STATUS_NEW;\r\n if (document.visibilityState !== \"visible\") {\r\n document.getElementById(\"favicon\").href = \"favicon-badged.ico\";\r\n messageQueue.current.push(message);\r\n if (messageQueue.current.length >= 10) {\r\n messageQueue.current.shift();\r\n }\r\n } else {\r\n dispatch(createMessage(message));\r\n }\r\n addHistoricalMessage(message);\r\n });\r\n\r\n socket.current.on(\"connect_error\", async (err) => {\r\n setConnected((prev) => {\r\n return Math.max(prev - 0.5, -100);\r\n });\r\n console.log(\"Socket connect error:\", err.message);\r\n\r\n if (err.message === \"user has not been registered\") {\r\n console.log(\"re registering\");\r\n await registerUser(token);\r\n }\r\n\r\n // You get disconnected for an old token, so refresh the token and reconnect\r\n const freshToken = await getAuth().currentUser.getIdToken();\r\n connectToSocket(freshToken, user);\r\n });\r\n\r\n socket.current.on(\"connect\", () => {\r\n setConnected(1);\r\n console.log(\"Connected to socket\");\r\n socket.current.emit(\"language\", getLanguage());\r\n });\r\n\r\n socket.current.on(\"warning\", (warning) => {\r\n //setBanWarning(warning);\r\n if (warning.type === \"RATE_LIMITED\") {\r\n console.log(\"rate limited\", warning.time);\r\n setSendEnabled(false);\r\n setTimeout(() => {\r\n setSendEnabled(true);\r\n }, warning.time * 950); // Enable 5% sooner than the actual time\r\n }\r\n });\r\n\r\n socket.current.on(\"status\", async (status) => {\r\n console.log(\"status\", status);\r\n if (status === \"NOT_VERIFIED\") {\r\n setModalIsOpen(true);\r\n } else if (status === \"LANG_RECEIVED\") {\r\n if (reconnect === false) {\r\n socket.current.emit(\"status\", \"CONNECTED\");\r\n const result = await fetch(\r\n API_URL + `messages?language=${getLanguage()}`,\r\n {\r\n method: \"GET\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: \"Bearer \" + token,\r\n },\r\n }\r\n );\r\n const historicalMessagesFromBackend = await result.json();\r\n historicalMessages.current = historicalMessagesFromBackend.messages;\r\n onClickReplay(false);\r\n }\r\n }\r\n });\r\n }\r\n\r\n function sendMessage(messageText, token) {\r\n let message = {\r\n id: uuidv4(),\r\n messageText: messageText,\r\n status: MESSAGE_STATUS_NEW,\r\n token: token,\r\n };\r\n\r\n socket.current.emit(\"chat message\", message);\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"sent_message\", { messageLength: messageText.length });\r\n\r\n messagesSentCount.current++;\r\n if (messagesSentCount.current == 5) {\r\n toast.info(\r\n \"Enjoying VentScape? Leave feedback / suggestions in the Discord or Reddit! Links in the settings menu (top right cog button)\",\r\n {\r\n position: \"top-center\",\r\n autoClose: 10000,\r\n hideProgressBar: false,\r\n closeOnClick: true,\r\n pauseOnHover: true,\r\n draggable: true,\r\n progress: undefined,\r\n theme: \"dark\",\r\n onClose: () => {},\r\n }\r\n );\r\n }\r\n }\r\n\r\n async function phoneNumberReceived() {\r\n const token = await getAuth().currentUser.getIdToken();\r\n await registerUser(token);\r\n connectToSocket(token, getAuth().currentUser);\r\n }\r\n\r\n function getLanguage() {\r\n var language = navigator.language || navigator.userLanguage || \"en\";\r\n if (language.includes(\"en\")) {\r\n language = \"en\";\r\n }\r\n return language;\r\n }\r\n\r\n function onClickReplay(realClick = true) {\r\n if (!replaying && !recycling) {\r\n setReplaying(true);\r\n displayQueueMessage([...historicalMessages.current], 2000);\r\n messageQueue.current = [];\r\n }\r\n\r\n if (realClick) {\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"pressed_replay\");\r\n }\r\n }\r\n\r\n async function onClickRecycle() {\r\n if (!replaying && !recycling) {\r\n setRecycling(true);\r\n const token = await getAuth().currentUser.getIdToken();\r\n const response = await fetch(\r\n API_URL + `messages/random?language=${getLanguage()}`,\r\n {\r\n method: \"GET\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: \"Bearer \" + token,\r\n },\r\n }\r\n );\r\n const randomMessages = await response.json();\r\n console.log(randomMessages.messages);\r\n displayQueueMessage([...randomMessages.messages], 1000);\r\n messageQueue.current = [];\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"pressed_recycle\");\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n {\r\n const nextOpenState = !settingsMenuIsOpen;\r\n setSettingsMenuIsOpen((prevState) => !prevState);\r\n const analytics = getAnalytics();\r\n logEvent(analytics, \"pressed_settings\", {\r\n open: nextOpenState,\r\n });\r\n }}\r\n onClickRecycle={onClickRecycle}\r\n onClickReplay={onClickReplay}\r\n connected={connected}\r\n />\r\n {\r\n setModalIsOpen(false);\r\n }}\r\n onSuccess={phoneNumberReceived}>\r\n\r\n {\r\n setReachOutModalOpen(false);\r\n }}\r\n />\r\n {\r\n setOnboardingModalOpen(false);\r\n }}\r\n />\r\n {\r\n setOnboardingModalOpen(true);\r\n }}\r\n closeSettingsMenu={() => {\r\n setSettingsMenuIsOpen(false);\r\n }}>\r\n \r\n \r\n {/* \r\n */}\r\n \r\n );\r\n}\r\n\r\nexport default RoomV2;\r\n","import { combineReducers } from 'redux';\r\nimport {\r\n ADD_MESSAGE,\r\n UPDATE_MESSAGE,\r\n DELETE_MESSAGE,\r\n UPDATE_MESSAGES,\r\n CACHE_MESSAGE,\r\n POP_MESSAGE,\r\n} from './messages-actions';\r\n\r\nconst messagesById = (state = {}, action) => {\r\n switch (action.type) {\r\n case UPDATE_MESSAGE:\r\n case ADD_MESSAGE:\r\n return {\r\n ...state,\r\n [action.payload.message.id]: action.payload.message,\r\n };\r\n case UPDATE_MESSAGES:\r\n const updateMessagesState = { ...state };\r\n action.payload.messages.forEach((message) => {\r\n updateMessagesState[message.id] = message;\r\n });\r\n return updateMessagesState;\r\n case DELETE_MESSAGE:\r\n const removeMessagesState = { ...state };\r\n delete removeMessagesState[action.payload.id];\r\n return removeMessagesState;\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nconst allMessages = (state = [], action) => {\r\n switch (action.type) {\r\n case ADD_MESSAGE:\r\n return state.concat(action.payload.message.id);\r\n case DELETE_MESSAGE:\r\n return state.filter((id) => id !== action.payload.id);\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nconst CACHE_LENGTH = 5;\r\n\r\nconst cacheMessages = (state = [], action) => {\r\n switch (action.type) {\r\n case CACHE_MESSAGE:\r\n if (state.length >= CACHE_LENGTH) {\r\n return state.slice(1).concat(action.payload.message);\r\n }\r\n return state.concat(action.payload.message);\r\n case POP_MESSAGE:\r\n return state.slice(0, -1);\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nexport default combineReducers({\r\n byId: messagesById,\r\n allIds: allMessages,\r\n cached: cacheMessages,\r\n});\r\n","import { UPDATE_CONTAINER } from './container-actions';\r\n\r\nconst initialState = new DOMRect(0, 0, 0, 0);\r\n\r\nexport default (state = initialState, action) => {\r\n switch (action.type) {\r\n case UPDATE_CONTAINER:\r\n return action.payload.containerRect;\r\n default:\r\n return state;\r\n }\r\n};\r\n","/* eslint-disable import/no-anonymous-default-export */\r\n\r\nimport { UPDATE_UI } from './ui-actions';\r\n\r\nconst initialState = {};\r\n\r\nexport default (state = initialState, action) => {\r\n switch (action.type) {\r\n case UPDATE_UI:\r\n return {\r\n ...state,\r\n [action.payload.id]: action.payload.uiRect,\r\n };\r\n default:\r\n return state;\r\n }\r\n};\r\n","import { getOnboardingIndex } from \"../utils/localstorage\";\r\nimport {\r\n INCREMENT_ONBOARDING,\r\n ASSIGNED_TOOLTIP_TO_MESSAGE,\r\n} from \"./onboarding-actions\";\r\n\r\nconst messageToolTipIndexes = new Set([0, 2, 3]);\r\n\r\n/*\r\nOnboarding master list:\r\n0. All messages from real people\r\n1. Type here to enter a message\r\n2. All messages disappear automatically\r\n3. Each person has their own color\r\n4. Click here for settings\r\n*/\r\n\r\nexport default (\r\n state = { index: getOnboardingIndex(), needsMessage: true },\r\n action\r\n) => {\r\n switch (action.type) {\r\n case INCREMENT_ONBOARDING:\r\n state.index++;\r\n if (messageToolTipIndexes.has(state.index)) {\r\n state.needsMessage = true;\r\n } else {\r\n state.needsMessage = false;\r\n }\r\n return state;\r\n case ASSIGNED_TOOLTIP_TO_MESSAGE:\r\n state.needsMessage = false;\r\n return state;\r\n default:\r\n return state;\r\n }\r\n};\r\n","import './App.css';\r\nimport { createGlobalStyle } from 'styled-components';\r\nimport React, { useEffect, useState, useRef } from 'react';\r\nimport {\r\n BrowserRouter as Router,\r\n Switch,\r\n Route,\r\n Redirect,\r\n} from 'react-router-dom';\r\nimport { ModalProvider } from 'styled-react-modal';\r\nimport { Provider } from 'react-redux';\r\nimport { applyMiddleware, combineReducers, createStore } from 'redux';\r\nimport thunk from 'redux-thunk';\r\nimport Room from './components/room';\r\nimport RoomsMenu from './components/roomsMenu';\r\nimport { API_URL } from './constants/string-constants';\r\nimport { device } from './constants/device-sizes';\r\nimport RoomV2 from './components/v2/RoomV2';\r\nimport messagesReducer from './store/messages-reducer';\r\nimport containerReducer from './store/container-reducer';\r\nimport uiReducer from './store/ui-reducer';\r\nimport { setDarkMode } from './utils/localstorage';\r\nimport onboardingReducer from './store/onboarding-reducer';\r\n\r\nconst rootReducer = combineReducers({\r\n messages: messagesReducer,\r\n containerRect: containerReducer,\r\n ui: uiReducer,\r\n onboarding: onboardingReducer\r\n});\r\n\r\nconst store = createStore(rootReducer, applyMiddleware(thunk));\r\n\r\nconst GlobalStyles = createGlobalStyle`\r\n *,\r\n *::before,\r\n *::after {\r\n box-sizing: border-box;\r\n }\r\n\r\n :root {\r\n --ff-primary: 'Open Sans';\r\n --ff-secondary: 'Open Sans';\r\n --fw-light: 200;\r\n --fw-reg: 300;\r\n --fw-bold: 900;\r\n \r\n --clr-prim: #1e1e1e;\r\n --clr-sec: #e1e1e1;\r\n --clr-tert: #969696;\r\n --clr-bg: #121212;\r\n --clr-invert-bg: #ffffff;\r\n --clr-cached: #999999;\r\n \r\n --clr-green: #31a33d;\r\n --clr-red: #c72929;\r\n --clr-purple: #c073de;\r\n\r\n --clr-shadow: #000000;\r\n\r\n --fs-h1: 3.25rem;\r\n --fs-h2: 1.75rem;\r\n --fs-h3: 1.5rem;\r\n\r\n --fs-body-bold: 1.15rem;\r\n --fs-body: 1rem;\r\n --fs-body-small: .75rem;\r\n --main-padding: 1rem 1rem;\r\n }\r\n\r\n /* Large Screens */\r\n @media ${device.tablet} {\r\n :root {\r\n --fs-h1: 4.5rem;\r\n --fs-h2: 2.5rem;\r\n --fs-h3: 1.75rem;\r\n\r\n --fs-body-bold: 1.15rem;\r\n --fs-body: 1.125rem;\r\n --fs-body-small: 0.85rem;\r\n --msg-width: 25%;\r\n --main-padding: 1rem 4rem;\r\n --minimize-height: 7.9rem;\r\n }\r\n }\r\n\r\n /* super small screens */\r\n @media (max-width: 320px) {\r\n :root {\r\n --fs-h1: 3rem;\r\n --fs-h2: 1.25rem;\r\n --fs-h3: 1rem;\r\n\r\n --fs-body-bold: 1.1rem;\r\n --fs-body: 1rem;\r\n --fs-body-small: 0.75rem;\r\n\r\n --btn-spacing: 0.25rem;\r\n }\r\n }\r\n\r\n html {\r\n scroll-behavior: smooth;\r\n height: 100%;\r\n }\r\n\r\n body {\r\n width: 100%;\r\n height: 100%;\r\n background: var(--clr-bg);\r\n color: var(--clr-sec);\r\n font-family: var(--ff-primary);\r\n line-height: 1.6;\r\n transition: all 0.2s linear;\r\n }\r\n\r\n h1,\r\n h2,\r\n h3 {\r\n line-height: 1;\r\n margin: 0;\r\n }\r\n\r\n h1 {\r\n font-size: var(--fs-h1);\r\n }\r\n h2 {\r\n font-size: var(--fs-h2);\r\n }\r\n h3 {\r\n font-size: var(--fs-h3);\r\n }\r\n\r\n h1,\r\n h2,\r\n h3,\r\n p,\r\n i,\r\n div {\r\n // text select stuff\r\n }\r\n `;\r\n\r\nfunction App() {\r\n const instructions = useRef({\r\n title: 'Welcome to VentScape!',\r\n type: 'instructions',\r\n subtitle: 'let it out into the void\\nsee others doing the same in realtime',\r\n description:\r\n 'This is a site where you can anonymously vent whatever’s on your mind and see others doing the same in realtime.\\n\\nChoose a room from the list below and get venting!',\r\n });\r\n\r\n const errorMessage = useRef({\r\n title: 'Error - Failed to load Rooms',\r\n type: 'instructions',\r\n subtitle:\r\n \"Looks like you weren't able to load the list of rooms for some reason. Most likely due to a connection issue with your internet, but if not, please message me (the dev) on Discord\",\r\n });\r\n\r\n const [rooms, setRooms] = useState(false);\r\n\r\n useEffect(() => {\r\n setRooms(true);\r\n }, []);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n\r\nexport default App;\r\n","const reportWebVitals = onPerfEntry => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './index.css';\r\nimport App from './App';\r\nimport reportWebVitals from './reportWebVitals';\r\nimport { getAnalytics, logEvent } from 'firebase/analytics';\r\n\r\n// Firebase App (the core Firebase SDK) is always required and must be listed first\r\nimport { initializeApp } from 'firebase/app';\r\nvar firebaseConfig = {\r\n apiKey: 'AIzaSyB0H4TlU6AL3E-rrvrbVEqA71IsIJHAFTc',\r\n authDomain: 'ventscape-9f566.firebaseapp.com',\r\n projectId: 'ventscape-9f566',\r\n storageBucket: 'ventscape-9f566.appspot.com',\r\n messagingSenderId: '50234146469',\r\n appId: '1:50234146469:web:2b8f68a7ae3ea78ae3974c',\r\n measurementId: 'G-RSMEGEMRZZ',\r\n};\r\n\r\ninitializeApp(firebaseConfig);\r\nconst analytics = getAnalytics();\r\nlogEvent(analytics, 'app_started');\r\nconsole.log('?');\r\nReactDOM.render(\r\n \r\n \r\n ,\r\n document.getElementById('root')\r\n);\r\n\r\n// If you want to start measuring performance in your app, pass a function\r\n// to log results (for example: reportWebVitals(console.log))\r\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\r\nreportWebVitals();\r\n"],"sourceRoot":""}