\n {/*
\n )\n\n return (\n
\n
\n
\n {image}\n
\n {content}\n
\n
\n
\n {from}, {time} \n \n {status == \"undelivered\" ? \n ✖\n :\n status == \"delivered\" ? \n ✔\n :\n \"\" //if not undelivered or delivered, leave blank for now.\n }\n \n
\n {\n // status == \"undelivered\" ? \n //
\n // {/* TODO: Add undelivered icon */}\n // undelivered!\n //
\n \n // : \n\n // status == \"delivered\" ? \n //
\n // {/* TODO: Add delivered icon */}\n // delivered! \n //
\n // : \n // null\n }\n \n
\n );\n }\n}\nexport default MessageBubbleSent;","\nimport React, {Component} from \"react\";\n\nclass MessageBubbleSent extends Component{\n constructor(props){\n super(props);\n }\n\n render(){\n const {content, time, imageSrc} = this.props;\n\n if (!imageSrc && !content) {\n return null\n }\n\n const image = ( imageSrc == null || imageSrc.trim() === '' ?
: \n
\n )\n\n return (\n
\n
\n
\n {image}\n
\n {content}\n
\n
\n
\n {time}\n
\n
\n );\n }\n}\nexport default MessageBubbleSent;","import React, {Component} from \"react\";\n\nclass ToggleConversations extends Component {\n constructor(props){\n super(props);\n }\n\n render(){\n return (\n
\n )\n }\n}\n\nexport default ToggleConversations;","import React, { Component } from \"react\";\nclass SendMessageToolbar extends Component{\n constructor(props) {\n super(props);\n\n this.changeHandler = this.changeHandler.bind(this);\n this.resetImage = this.resetImage.bind(this);\n this.handleSend = this.handleSend.bind(this);\n this.resetData = this.resetData.bind(this);\n }\n\n changeHandler(event) {\n let src = event.target.value;\n if(src) {\n $('#image_avatar_url_id').val('');\n const url = window.URL.createObjectURL(event.target.files[0])\n\n $('#attached-image').attr('src',url);\n $('#attached-image-container').show();\n $('#image_upload').hide();\n }\n }\n\n resetImage() {\n $('#image_avatar').val('')\n $('#image_avatar_url_id').val('');\n $(\"#attached-image-container\").hide()\n $(\"#attached-image\").attr(\"src\", '');\n this.setState({ imageSrc: '', file: {}})\n }\n\n resetData() {\n this.resetImage();\n $('#message_to_send').val('');\n }\n\n handleSend() {\n const imageSrc = $('#attached-image').attr('src')\n const file = $('#image_avatar')[0].files[0] || {}\n const uploadedImageId = $('#image_avatar_url_id').val();\n\n const messagePayload = {\n image: {\n file: file,\n imageUrl: imageSrc,\n id: uploadedImageId\n },\n message: $('#message_to_send').val()\n }\n\n const { addNewMessageCallback } = this.props;\n addNewMessageCallback(messagePayload, this.resetData); \n }\n\n render(){\n\n return(\n
\n )\n }\n}\n\nexport default SendMessageToolbar;","import React, { Component } from \"react\";\nclass NewConversationButton extends Component{\n constructor(props) {\n super(props);\n }\n\n render(){\n const {selectNewConversationThreadCallback} = this.props;\n return(\n
\n )\n }\n}\n\nexport default NewConversationButton;","import React, { Component } from 'react';\n\nclass TableBody extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n const { tableData } = this.props;\n\n return (\n
\n {\n tableData.map((data, index) => (\n \n { data.resource } | \n { data.action } | \n { this._toolsColumnField(data) }\n
\n ))\n }\n \n );\n }\n\n _toolsColumnField(data) {\n const { displayTools } = this.props;\n\n if( displayTools ) {\n return(\n
\n \n \n \n \n \n \n | \n );\n } else {\n return null;\n }\n }\n}\n\nexport default TableBody;\n","import React, { Component } from \"react\";\n\nclass TableHeader extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n const { displayTools } = this.props;\n\n return (\n
\n \n Resource | \n Action | \n { this._toolsColumnHeader() }\n
\n \n );\n }\n\n _toolsColumnHeader() {\n const { displayTools } = this.props;\n\n if( displayTools ) {\n return(
| );\n } else {\n return null;\n }\n }\n}\n\nexport default TableHeader;\n","import React, { Component } from 'react';\nimport TableData from \"./TableData\";\nimport DateRangePicker from \"./DateRangePicker\";\n\nclass IndexPage extends Component {\n constructor(props){\n super(props);\n\n this.openSearchBar = this.openSearchBar.bind(this);\n }\n\n openSearchBar() {\n const search = prompt(\"Search\");\n const data = document.getElementsByClassName('tdData');\n\n if (search != null) {\n for (let d = 0; d < data.length; d++) {\n const text = data[d].innerText.split(\" \");\n\n for (let i = 0; i < text.length; i++) {\n let index = text[i];\n let splitIndex = index.split(\"\");\n if (index.toLowerCase().includes(search.toLowerCase())) {\n for (let si = 0; si < index.length; si++) {\n if (search.toLowerCase().includes(index[si].toLowerCase())) {\n splitIndex[si] = `
${index[si]}`;\n text[i] = splitIndex.join(\"\");\n }\n }\n }\n }\n\n data[d].innerHTML = text.join(\" \");\n }\n }\n }\n\n render(){\n const {title, attributes, data, basePath, updateProduct, removeProduct, handleProductPriceSorting, handleProductNameSorting, showNewProductButton} = this.props; \n return(\n
\n \n \n {\n this.props.showDatePicker && \n }\n\n \n );\n }\n}\n\nexport default IndexPage;","import React, { Component } from \"react\";\nimport ContentEditable from \"react-contenteditable\"\n\n/**\n * The contractor who edited this recently broke the single responsibility issue and did not keep the proper level of abstraction here. \n * So now, this component is tightly coupled with the \"product\" table, thus breaking our abstraction and introducing a whole host of issues. \n * So this class should not be reused by other components until it is uncoupled and we put the correct level of abstraction back to it. \n */\nclass TableData extends Component{\n constructor(props){\n super(props)\n\n this.addNewProduct = this.addNewProduct.bind(this);\n this.saveProductsData = this.saveProductsData.bind(this);\n this.removeProductsRow = this.removeProductsRow.bind(this);\n this.productAttrUpdate = this.productAttrUpdate.bind(this);\n }\n\n addNewProduct(){\n const { updateProduct } = this.props;\n const data = [\n \"\",\n {\n \"title\": \"\",\n \"url\": \"products/\"\n },\n \"\",\n 0,\n \"\"\n ];\n\n updateProduct(data);\n }\n\n removeProductsRow(event) {\n const { removeProduct, data } = this.props;\n const { index:productTotalIndex } = $(event.currentTarget).parents('tr')?.data()\n removeProduct(productTotalIndex)\n }\n\n render(){\n const {title, attributes, data, basePath, actions, showNewProductButton } = this.props;\n const responsiveStyleWrapper = {\n overflowX: \"auto\"\n }\n\n var showActions = actions;\n if (showActions == null){ //These are the default actions\n showActions = {delete: true, edit: true, view: true}\n }\n\n const tableHeaders = this._buildTopRow(attributes);\n const tableData = this._buildTableBodyRows(data, basePath, showActions); \n return(\n
\n
\n \n \n {tableHeaders}\n Actions | \n
\n \n \n {tableData}\n \n
\n {showNewProductButton \n ? \n
\n : \n
\n }\n \n
\n );\n };\n\n _buildTopRow(attributes){\n const { handleProductNameSorting, handleProductPriceSorting } = this.props;\n const tableHeaders = [];\n for (const [index, value] of attributes.entries()){\n const titleizedValue = value.replace(/^\\w/, c => c.toUpperCase());\n tableHeaders.push(\n
\n {\n value == 'name' || value == 'price'\n ? handleProductNameSorting()\n : () => handleProductPriceSorting()\n }\n style={{\n textDecoration: \"none\",\n color: \"#555555\"\n }}\n >\n {titleizedValue} ⇵\n \n : titleizedValue\n }\n | \n );\n };\n return tableHeaders;\n }\n\n _buildTableBodyRows(data, basePath, actions){\n const tableData = [];\n for (const [index, value] of data.entries()){\n const row = [];\n const productId = value[0]; //First element is always the id\n for (const [objectIndex, objectValue] of value.entries()){\n const lookingAtObjectsId = objectIndex == 0;\n const lookingAtUrlObject = objectValue != null && objectValue[\"url\"] != null;\n let attrName = '';\n if (lookingAtObjectsId){ //We don't want to add a
just for the ID. \n continue;\n }\n else if (lookingAtUrlObject){\n const openInNewTab = objectValue[\"newtab\"] != null;\n const icon = objectValue[\"icon\"] == null ? null : ( {objectValue[\"title\"]} );\n const iconFullClass = objectValue[\"iconclass\"] == null ? null : ( {objectValue[\"title\"]} ); // This extra one is because some icons don't start with 'fas', they might start with 'fab', like in the case with the stripe icon. \n const displayText = icon == null && iconFullClass == null ? objectValue[\"title\"] : icon || iconFullClass\n const linkClass = objectValue[\"class\"] != null ? objectValue[\"class\"] : \"\";\n const hover = objectValue[\"hover\"] != null ? objectValue[\"hover\"] : \"\";\n const target = openInNewTab ? \"_blank\" : \"\";\n // row.push( | {displayText} | )\n row.push(
| )\n }\n else {\n if(objectIndex == 2){\n attrName = 'description';\n } else if(objectIndex == 3){\n attrName = 'price';\n } else if(objectIndex == 4){\n attrName = 'SKU';\n } else{\n attrName = '';\n }\n \n row.push(
\n \n | )\n }\n }\n \n row.push(\n this.actionsTd(productId, basePath, actions)\n );\n tableData.push(
{row}
)\n };\n return tableData;\n }\n\n actionsTd(productId, basePath, actions) {\n if(!productId)\n {\n return
\n \n \n \n \n | ;\n \n }\n var viewElement = null;\n if (actions.view){\n viewElement = \n (
); \n }\n \n var editElement = null;\n if (actions.edit){\n editElement = \n (
); \n }\n\n var deleteElement = null;\n if (actions.delete){\n deleteElement = \n (
);\n }\n\n return
\n \n {viewElement}\n {editElement}\n {deleteElement}\n \n | ;\n }\n\n productAttrUpdate(event){\n const { updateProduct } = this.props;\n const id = $(event.currentTarget).parents('tr').attr('id')\n const attr = event.currentTarget.id;\n const attrVal = event.currentTarget.innerText;\n const attrName = attr.charAt(0).toUpperCase() + attr.slice(1);\n const { index:productTotalIndex } = $(event.currentTarget).parents('tr')?.data();\n\n if(id != '') {\n $.ajax({\n url: `/products/${id}/update_attribute`,\n method: \"PUT\",\n data: {attribute: attr, value: attrVal},\n success: function(data){\n gritterSuccess(\"Success\", `${attrName} Updated Successfully`);\n },\n error: function(data){\n gritterError(\"Error\", \"Something Error\", \"10000\");\n }\n })\n }\n\n const newData = [...this.props.data[productTotalIndex]];\n const colIndex = $(event.currentTarget).parent('td').attr('data-index');\n colIndex == 1\n ? newData[colIndex] = {\n title: event.currentTarget.innerText,\n url: '/products'\n }\n : newData[colIndex] = event.currentTarget.innerText;\n\n updateProduct(newData, productTotalIndex);\n }\n\n saveProductsData(event) {\n const createButton = event.currentTarget;\n createButton.disabled = true;\n const { updateProduct } = this.props;\n\n const currentRow = $(createButton).parents('tr').children();\n \n const pName = currentRow[0].innerText;\n const pDesc = currentRow[1].innerText;\n const pPrice = currentRow[2].innerText;\n const pSku = currentRow[3].innerText;\n const { index:productTotalIndex } = $(createButton).parents('tr')?.data();\n\n const product = {name: pName, description: pDesc, price: pPrice, SKU: pSku}\n $.ajax({\n url: `/products.json`,\n method: \"POST\",\n data: {product: product},\n success: function(data){\n const newData = [\n data.id,\n {\n \"title\": data.name,\n \"url\": `products/${data.id}`\n },\n data.description,\n data.price,\n data.SKU\n ];\n\n updateProduct(newData, productTotalIndex);\n gritterSuccess(\"Success\", `Product Added Successfully`);\n },\n error: function(data){\n createButton.disabled = false;\n gritterError(\"Error\", \"Something Error\", \"10000\");\n }\n })\n }\n}\n\nexport default TableData;","// Filename - Progress_bar.js\n \nimport React from 'react'\n \nconst ProgressBar = ({bgcolor,progress,height}) => {\n const Parentdiv = {\n height: height,\n width: '80%',\n backgroundColor: 'whitesmoke',\n borderRadius: 40,\n margin: 50\n }\n \n const Childdiv = {\n height: '100%',\n width: `${progress}%`,\n backgroundColor: bgcolor,\n borderRadius:40,\n textAlign: 'right'\n }\n \n const progresstext = {\n padding: 10,\n color: 'black',\n fontWeight: 900\n }\n \n return (\n
\n
\n {/* {`${progress}%`} */}\n {\"\"}\n
\n
\n )\n}\n \nexport default ProgressBar;","import React, {Component} from \"react\";\nimport LogoPath from \"images/fieldrocketlogo.png\"\n\nconst FieldRocketLogo = () => {\n return(\n
\n )\n}\n\nexport default FieldRocketLogo;","import React from \"react\";\n\nconst FRPillButton = ({onClick, text, disabled=false}) => {\n return(\n disabled\n ?\n
\n :\n
\n )\n}\n\nexport default FRPillButton;","import React, {useState, useEffect} from \"react\";\nimport InputField from \"../../shared/Forms/InputField\";\nimport EmailInputField from \"../../shared/Forms/EmailInputField\";\n\nconst WhatsYourNameStep = ({ firstName, setFirstName, businessName, setBusinessName, email, setEmail, setEnableNextButton }) => {\n\n useEffect(() => { //all of these need to be true in order to be valid.\n setEnableNextButton(!isBlank(firstName) && !isBlank(businessName) && !isBlank(email) && isValidEmail(email));\n // setEnableNextButton(true);\n }, [firstName, businessName, email])\n\n return (\n
\n
!isBlank(name)}\n />\n \n !isBlank(name)}\n />\n \n \n {/* \n
\n \n setEmail(e.target.value)}\n onBlur={e => validateEmailInput(e.target.value)}\n style={{borderColor: emailIsValid ? \"\" : 'red'}}\n />\n
\n
*/}\n \n );\n}\n\n\nexport default WhatsYourNameStep;\n","import React, {useState} from \"react\";\nimport InputField from \"./InputField\";\n\nconst EmailInputField = ({id, email, setEmail}) => {\n const [emailIsValid, setEmailIsValid] = useState(true);\n const [invalidMessage, setInvalidMessage] = useState(\"\");\n\n const validateEmailInput = (userInputtedEmail) => {\n\n if (isValidEmail(userInputtedEmail)){\n console.log(`Email ${userInputtedEmail} is valid!`)\n setEmailIsValid(true);\n return true;\n } \n else {\n console.log(`Email ${userInputtedEmail} is NOT valid!`)\n setEmailIsValid(false);\n setInvalidMessage(\"Email: Please enter a valid email address.\");\n return false;\n }\n } \n\n return(\n
\n )\n}\n\nexport default EmailInputField;","import React, {useEffect} from \"react\";\nimport InputField from \"../../shared/Forms/InputField\";\n\n//NOTE: This must match the same surveyUserOptions in the GetStarted.jsx to make sure the server gets the right info.\nconst userOptions = [\n \"Invoicing & Payments\", \"Estimates & Closing\", \"Scheduling Customers\", \"Growth & Marketing\", \"Other\"\n];\n\n// const surveyUserOptions = [\"Invoicing & Payments\", \"Estimates & Closing\", \"Scheduling Customers\", \"Growth & Marketing\", \"Other\"];\n\nconst AskUserHighestPrioritySurveyOnRegistration = ({\n surveyAnswer,\n setSurveyAnswer,\n freeFormSurveyAnswer,\n setFreeFormSurveyAnswer,\n setEnableNextButton\n}) => {\n \n useEffect(() => {\n let nextButtonShouldBeEnabled = surveyAnswer != undefined && surveyAnswer != null && surveyAnswer >= 0;\n \n if (surveyAnswer == 4) {//3 is hardcoded to be the \"other\" selection.\n nextButtonShouldBeEnabled = !isBlank(freeFormSurveyAnswer) // is not blank\n console.log(!isBlank(freeFormSurveyAnswer));\n }\n\n console.log(\"Survey answer is: \" + userOptions[surveyAnswer])\n\n setEnableNextButton(nextButtonShouldBeEnabled);\n\n }, [surveyAnswer, freeFormSurveyAnswer])\n\n return (\n
\n
\n {/*
What Is The Main Thing You Hope To Accomplish With Field Rocket?
*/}\n
Pick one.
\n\n {userOptions.map((item, index) => (\n
\n \n
\n ))}\n\n {surveyAnswer === 4 && (\n
!isBlank(answer)}\n />\n // \n
\n );\n};\n\nexport default AskUserHighestPrioritySurveyOnRegistration;","import React, {useEffect, useState} from \"react\";\nimport InputField from \"../../shared/Forms/InputField\";\n\nconst PhoneNumberStep = ({ phone, setPhone, setEnableNextButton }) => {\n const [isValid, setIsValid] = useState(true);\n const [invalidMessage, setInvalidMessage] = useState(\"\");\n\n /**\n * This is a super annoying hack, because phone-mask.js for some reason isn't running on this page after the \n * className is set properly in InputField. So I'm just re-running the code needed to add the formatting for the\n * phone number here.\n */\n useEffect(() => {\n $('.phone_mask').mask('(000) 000-0000');\n $('.phone_mask').bind('paste', (event) => { //I added this in so that you could copy and paste from iPhone phone numbers into the app.. the +1 was throwing off our phone_masking. \n var pastedData = event.originalEvent.clipboardData.getData('text')\n if (pastedData[0] == \"+\" && pastedData[1] == \"1\"){\n let filteredPhoneNumber = pastedData.substring(2); //trim out the +1 from phone number if it exists..\n console.log(`Modified Pasted phone number from: ${pastedData} to: ${filteredPhoneNumber}!`);\n // event.originalEvent.clipboardData.setData('text/plain', filteredPhoneNumber);\n event.target.value = filteredPhoneNumber\n }\n });\n })\n\n useEffect(() => {\n let formattedPhoneNumber = formatPhoneNumber(phone);\n let isValid = isValidPhoneNumber(formattedPhoneNumber);\n setEnableNextButton(isValid);\n }, [phone])\n\n const onValidatePhoneNumber = (phoneNumber) => {\n let formattedPhoneNumber = formatPhoneNumber(phoneNumber);\n let isValid = isValidPhoneNumber(formattedPhoneNumber);\n if (isValid) {\n setInvalidMessage(\"\");\n setIsValid(true);\n return true;\n }\n else {\n setInvalidMessage(\"Please enter a full phone number\")\n setIsValid(false);\n return false;\n }\n }\n\n return (\n
\n \n
\n );\n}\n\nexport default PhoneNumberStep;\n","import React from \"react\";\n\nconst ConfirmAccessCodeStep = ({ accessCode, setAccessCode }) => {\n return (\n
\n
\n \n setAccessCode(e.target.value)}\n placeholder=\"Enter your access code\"\n />\n
\n
\n );\n}\n\nexport default ConfirmAccessCodeStep;\n","import React from \"react\";\nimport AppleIcon from 'images/social/apple-Icon-metro.svg'; // Adjust the path as per your directory structure\nimport AndroidIcon from 'images/social/android-Icon-material.svg'; // Adjust the path as per your directory structure\n\nconst DoneStep = ({email}) => {\n return (\n
\n
\n
After setting your password, make sure to click \"Already have an account?\"
\n {/*
*/}\n
\n
\n
\n
\n
\n
\n
\n );\n}\n\nexport default DoneStep;","import React, {useEffect} from \"react\";\nimport InputField from \"../../shared/Forms/InputField\";\n\nconst HowDidYouHearAboutUs = ({\n howDidYouHearAboutUsAnswer,\n setHowDidYouHearaboutUsAnswer,\n setEnableNextButton\n}) => {\n \n useEffect(() => {\n let nextButtonShouldBeEnabled = howDidYouHearAboutUsAnswer != undefined && howDidYouHearAboutUsAnswer != null && !isBlank(howDidYouHearAboutUsAnswer);\n setEnableNextButton(nextButtonShouldBeEnabled);\n }, [howDidYouHearAboutUsAnswer])\n\n return (\n
\n
\n {/*
How did you hear about Field Rocket?
*/}\n
!isBlank(answer)}\n />\n \n
\n );\n};\n\nexport default HowDidYouHearAboutUs;","import React, { Component } from 'react';\nimport TableBody from \"./TableBody\";\nimport TableHeader from \"./TableHeader\";\n\nclass Table extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n const { tableData, permissions } = this.props;\n\n return (\n
\n );\n }\n}\n\nexport default Table;\n","import React, { Component } from 'react';\n\nclass TableBody extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n const { tableData } = this.props;\n\n return (\n
\n {\n tableData.map((data, index) => (\n \n { data.name } | \n { this._tools(data) }\n
\n ))\n }\n \n );\n }\n\n _tools(data) {\n const { permissions } = this.props;\n\n if( permissions[\"destroy\"] && permissions[\"update\"] ) {\n return(\n
\n \n \n \n | \n );\n } else if( permissions[\"destroy\"] ) {\n return(\n
\n \n \n \n | \n );\n } else if( permissions[\"update\"] ) {\n return(\n
\n | \n );\n } else {\n return(\n
\n | \n );\n }\n }\n}\n\nexport default TableBody;\n","import React, { Component } from \"react\";\nimport SortLink from \"../shared/SortLink\";\n\nclass TableHeader extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n return (\n
\n \n Roster Name | \n
\n \n );\n }\n}\n\nexport default TableHeader;\n","import React, { Component } from \"react\";\n\nclass TableTop extends Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n return (\n
\n { this._newLink() }\n
\n );\n }\n\n _newLink() {\n const { permissions } = this.props;\n\n if( permissions[\"create\"] ) {\n return(
);\n } else {\n return null;\n }\n }\n}\n\nexport default TableTop;\n","import React, {Component} from \"react\";\nimport { ToggleButtonGroup, ToggleButton } from \"@mui/material\";\n\nclass SimpleToggleButtonGroup extends Component{\n constructor(props){\n super(props); \n\n this.state = {\n selectedValue: this.props.items[0]\n }\n\n this.setSelectedValue = this.setSelectedValue.bind(this);\n }\n\n setSelectedValue = (changeEvent) => {\n const newValue = changeEvent.target.value;\n this.setState({...this.state, selectedValue: newValue})\n if (this.props.onChange != null){\n this.props.onChange(newValue);\n }\n }\n\n render(){\n const {items} = this.props;\n return(\n
\n {items.map((item) => (\n {item}\n ))}\n \n )\n \n }\n}\n\nexport default SimpleToggleButtonGroup;","import React, {useState, useEffect} from \"react\";\nimport TimesheetsTable from \"./TimesheetTable\";\n\nexport default function EmployeeTimesheetHeader({employeeId, timesheets}){\n const [isOpen, setIsOpen] = useState(false);\n const [employeeHeaderInfo, setEmployeeHeaderInfo] = useState(null);\n const [duration, setDuration] = useState(\"\");\n const [currentTimesheets, setCurrentTimesheets] = useState(timesheets);\n\n useEffect(() => { // An AJAX request to the server to request the employeeHeaderInfo that will have all sorts of info we need to render this component.\n if (employeeId == \"\" || employeeId == null){\n setEmployeeHeaderInfo({\"employee_full_name\": \"Unassigned\"})\n }\n else {\n $.get(\n {url: `/employees/${employeeId}/info`, \n success: function(data){\n console.log(data);\n setEmployeeHeaderInfo(data);\n }\n })\n }\n }, [])\n\n useEffect(() => {\n setDuration(formatDuration(totalDurationForTheseTimesheets()));\n }, [currentTimesheets])\n\n const totalDurationForTheseTimesheets = () => {\n const durationSum = currentTimesheets.map((timesheet) => timesheet.duration).reduce((sumSoFar, duration) => sumSoFar + duration);\n return durationSum;\n }\n\n return(\n
\n
{setIsOpen(!isOpen)}}\n style={{borderRadius: 13}}>\n
\n {timesheets[0] == null ? '...' : formatReadableDate(timesheets[0][\"clocked_in\"])}\n
\n
\n
{employeeHeaderInfo == null ? 'Loading ...' : employeeHeaderInfo[\"full_name\"]}
\n \n \n
\n {duration}\n
\n
\n {isOpen ? : }\n
\n
\n
\n {isOpen && }\n
\n
\n )\n}","import React, {useState, useEffect} from \"react\";\nimport TimesheetsTable from \"./TimesheetTable\";\n\nexport default function JobTimesheetHeader({jobId, timesheets}){\n const [isOpen, setIsOpen] = useState(false);\n const [jobHeaderInfo, setJobHeaderInfo] = useState(null);\n const [duration, setDuration] = useState(\"\");\n const [currentTimesheets, setCurrentTimesheets] = useState(timesheets);\n\n useEffect(() => { // An AJAX request to the server to request the jobHeaderInfo that will have all sorts of info we need to render this component.\n if (jobId == \"\" || jobId == null){\n setJobHeaderInfo({\"customer_full_name\": \"General Time\"})\n }\n else {\n $.get(\n {url: `/jobs/${jobId}.json`, \n success: function(data){\n console.log(data);\n setJobHeaderInfo(data);\n }\n })\n }\n }, [])\n\n useEffect(() => {\n setDuration(formatDuration(totalDurationForTheseTimesheets()));\n }, [currentTimesheets])\n\n const totalDurationForTheseTimesheets = () => {\n const durationSum = currentTimesheets.map((timesheet) => timesheet.duration).reduce((sumSoFar, duration) => sumSoFar + duration);\n return durationSum;\n }\n\n return(\n
\n
{setIsOpen(!isOpen)}}\n style={{borderRadius: 13}}>\n
\n {jobHeaderInfo == null ? '...' : formatReadableDate(jobHeaderInfo[\"updated_at\"])}\n
\n
\n
{jobHeaderInfo == null ? 'Loading ...' : jobHeaderInfo[\"customer_full_name\"]}
\n \n
\n {jobHeaderInfo == null ? '...' : jobHeaderInfo[\"display_address\"]}\n
\n \n
\n {duration}\n
\n
\n {isOpen ? : }\n
\n
\n
\n {isOpen && }\n
\n
\n )\n}","function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : String(i); }\nfunction _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\n/**\n * Custom positioning reference element.\n * @see https://floating-ui.com/docs/virtual-elements\n */\n\nconst sides = ['top', 'right', 'bottom', 'left'];\nconst alignments = ['start', 'end'];\nconst placements = /*#__PURE__*/sides.reduce((acc, side) => acc.concat(side, side + \"-\" + alignments[0], side + \"-\" + alignments[1]), []);\nconst min = Math.min;\nconst max = Math.max;\nconst round = Math.round;\nconst floor = Math.floor;\nconst createCoords = v => ({\n x: v,\n y: v\n});\nconst oppositeSideMap = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nconst oppositeAlignmentMap = {\n start: 'end',\n end: 'start'\n};\nfunction clamp(start, value, end) {\n return max(start, min(value, end));\n}\nfunction evaluate(value, param) {\n return typeof value === 'function' ? value(param) : value;\n}\nfunction getSide(placement) {\n return placement.split('-')[0];\n}\nfunction getAlignment(placement) {\n return placement.split('-')[1];\n}\nfunction getOppositeAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}\nfunction getAxisLength(axis) {\n return axis === 'y' ? 'height' : 'width';\n}\nfunction getSideAxis(placement) {\n return ['top', 'bottom'].includes(getSide(placement)) ? 'y' : 'x';\n}\nfunction getAlignmentAxis(placement) {\n return getOppositeAxis(getSideAxis(placement));\n}\nfunction getAlignmentSides(placement, rects, rtl) {\n if (rtl === void 0) {\n rtl = false;\n }\n const alignment = getAlignment(placement);\n const alignmentAxis = getAlignmentAxis(placement);\n const length = getAxisLength(alignmentAxis);\n let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';\n if (rects.reference[length] > rects.floating[length]) {\n mainAlignmentSide = getOppositePlacement(mainAlignmentSide);\n }\n return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];\n}\nfunction getExpandedPlacements(placement) {\n const oppositePlacement = getOppositePlacement(placement);\n return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];\n}\nfunction getOppositeAlignmentPlacement(placement) {\n return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);\n}\nfunction getSideList(side, isStart, rtl) {\n const lr = ['left', 'right'];\n const rl = ['right', 'left'];\n const tb = ['top', 'bottom'];\n const bt = ['bottom', 'top'];\n switch (side) {\n case 'top':\n case 'bottom':\n if (rtl) return isStart ? rl : lr;\n return isStart ? lr : rl;\n case 'left':\n case 'right':\n return isStart ? tb : bt;\n default:\n return [];\n }\n}\nfunction getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {\n const alignment = getAlignment(placement);\n let list = getSideList(getSide(placement), direction === 'start', rtl);\n if (alignment) {\n list = list.map(side => side + \"-\" + alignment);\n if (flipAlignment) {\n list = list.concat(list.map(getOppositeAlignmentPlacement));\n }\n }\n return list;\n}\nfunction getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, side => oppositeSideMap[side]);\n}\nfunction expandPaddingObject(padding) {\n return _objectSpread({\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n }, padding);\n}\nfunction getPaddingObject(padding) {\n return typeof padding !== 'number' ? expandPaddingObject(padding) : {\n top: padding,\n right: padding,\n bottom: padding,\n left: padding\n };\n}\nfunction rectToClientRect(rect) {\n return _objectSpread(_objectSpread({}, rect), {}, {\n top: rect.y,\n left: rect.x,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}\nexport { alignments, clamp, createCoords, evaluate, expandPaddingObject, floor, getAlignment, getAlignmentAxis, getAlignmentSides, getAxisLength, getExpandedPlacements, getOppositeAlignmentPlacement, getOppositeAxis, getOppositeAxisPlacements, getOppositePlacement, getPaddingObject, getSide, getSideAxis, max, min, placements, rectToClientRect, round, sides };","function getNodeName(node) {\n if (isNode(node)) {\n return (node.nodeName || '').toLowerCase();\n }\n // Mocked nodes in testing environments may not be instances of Node. By\n // returning `#document` an infinite loop won't occur.\n // https://github.com/floating-ui/floating-ui/issues/2317\n return '#document';\n}\nfunction getWindow(node) {\n var _node$ownerDocument;\n return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;\n}\nfunction getDocumentElement(node) {\n var _ref;\n return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;\n}\nfunction isNode(value) {\n return value instanceof Node || value instanceof getWindow(value).Node;\n}\nfunction isElement(value) {\n return value instanceof Element || value instanceof getWindow(value).Element;\n}\nfunction isHTMLElement(value) {\n return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;\n}\nfunction isShadowRoot(value) {\n // Browsers without `ShadowRoot` support.\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;\n}\nfunction isOverflowElement(element) {\n const _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY,\n display = _getComputedStyle.display;\n return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);\n}\nfunction isTableElement(element) {\n return ['table', 'td', 'th'].includes(getNodeName(element));\n}\nfunction isContainingBlock(element) {\n const webkit = isWebKit();\n const css = getComputedStyle(element);\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n return css.transform !== 'none' || css.perspective !== 'none' || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || ['transform', 'perspective', 'filter'].some(value => (css.willChange || '').includes(value)) || ['paint', 'layout', 'strict', 'content'].some(value => (css.contain || '').includes(value));\n}\nfunction getContainingBlock(element) {\n let currentNode = getParentNode(element);\n while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {\n if (isContainingBlock(currentNode)) {\n return currentNode;\n } else {\n currentNode = getParentNode(currentNode);\n }\n }\n return null;\n}\nfunction isWebKit() {\n if (typeof CSS === 'undefined' || !CSS.supports) return false;\n return CSS.supports('-webkit-backdrop-filter', 'none');\n}\nfunction isLastTraversableNode(node) {\n return ['html', 'body', '#document'].includes(getNodeName(node));\n}\nfunction getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\nfunction getNodeScroll(element) {\n if (isElement(element)) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n }\n return {\n scrollLeft: element.pageXOffset,\n scrollTop: element.pageYOffset\n };\n}\nfunction getParentNode(node) {\n if (getNodeName(node) === 'html') {\n return node;\n }\n const result =\n // Step into the shadow DOM of the parent of a slotted node.\n node.assignedSlot ||\n // DOM Element detected.\n node.parentNode ||\n // ShadowRoot detected.\n isShadowRoot(node) && node.host ||\n // Fallback.\n getDocumentElement(node);\n return isShadowRoot(result) ? result.host : result;\n}\nfunction getNearestOverflowAncestor(node) {\n const parentNode = getParentNode(node);\n if (isLastTraversableNode(parentNode)) {\n return node.ownerDocument ? node.ownerDocument.body : node.body;\n }\n if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {\n return parentNode;\n }\n return getNearestOverflowAncestor(parentNode);\n}\nfunction getOverflowAncestors(node, list, traverseIframes) {\n var _node$ownerDocument2;\n if (list === void 0) {\n list = [];\n }\n if (traverseIframes === void 0) {\n traverseIframes = true;\n }\n const scrollableAncestor = getNearestOverflowAncestor(node);\n const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);\n const win = getWindow(scrollableAncestor);\n if (isBody) {\n return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], win.frameElement && traverseIframes ? getOverflowAncestors(win.frameElement) : []);\n }\n return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));\n}\nexport { getComputedStyle, getContainingBlock, getDocumentElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isWebKit };","function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : String(i); }\nfunction _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }\nfunction _iterableToArrayLimit(r, l) { var t = null == r ? null : \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\nimport { rectToClientRect, autoPlacement as autoPlacement$1, shift as shift$1, flip as flip$1, size as size$1, hide as hide$1, arrow as arrow$1, inline as inline$1, limitShift as limitShift$1, computePosition as computePosition$1 } from '@floating-ui/core';\nexport { detectOverflow, offset } from '@floating-ui/core';\nimport { round, createCoords, max, min, floor } from '@floating-ui/utils';\nimport { getComputedStyle, isHTMLElement, isElement, getWindow, isWebKit, getContainingBlock, getDocumentElement, getNodeName, isOverflowElement, getNodeScroll, getOverflowAncestors, getParentNode, isLastTraversableNode, isContainingBlock, isTableElement } from '@floating-ui/utils/dom';\nexport { getOverflowAncestors } from '@floating-ui/utils/dom';\nfunction getCssDimensions(element) {\n const css = getComputedStyle(element);\n // In testing environments, the `width` and `height` properties are empty\n // strings for SVG elements, returning NaN. Fallback to `0` in this case.\n let width = parseFloat(css.width) || 0;\n let height = parseFloat(css.height) || 0;\n const hasOffset = isHTMLElement(element);\n const offsetWidth = hasOffset ? element.offsetWidth : width;\n const offsetHeight = hasOffset ? element.offsetHeight : height;\n const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;\n if (shouldFallback) {\n width = offsetWidth;\n height = offsetHeight;\n }\n return {\n width,\n height,\n $: shouldFallback\n };\n}\nfunction unwrapElement(element) {\n return !isElement(element) ? element.contextElement : element;\n}\nfunction getScale(element) {\n const domElement = unwrapElement(element);\n if (!isHTMLElement(domElement)) {\n return createCoords(1);\n }\n const rect = domElement.getBoundingClientRect();\n const _getCssDimensions = getCssDimensions(domElement),\n width = _getCssDimensions.width,\n height = _getCssDimensions.height,\n $ = _getCssDimensions.$;\n let x = ($ ? round(rect.width) : rect.width) / width;\n let y = ($ ? round(rect.height) : rect.height) / height;\n\n // 0, NaN, or Infinity should always fallback to 1.\n\n if (!x || !Number.isFinite(x)) {\n x = 1;\n }\n if (!y || !Number.isFinite(y)) {\n y = 1;\n }\n return {\n x,\n y\n };\n}\nconst noOffsets = /*#__PURE__*/createCoords(0);\nfunction getVisualOffsets(element) {\n const win = getWindow(element);\n if (!isWebKit() || !win.visualViewport) {\n return noOffsets;\n }\n return {\n x: win.visualViewport.offsetLeft,\n y: win.visualViewport.offsetTop\n };\n}\nfunction shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element)) {\n return false;\n }\n return isFixed;\n}\nfunction getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n const clientRect = element.getBoundingClientRect();\n const domElement = unwrapElement(element);\n let scale = createCoords(1);\n if (includeScale) {\n if (offsetParent) {\n if (isElement(offsetParent)) {\n scale = getScale(offsetParent);\n }\n } else {\n scale = getScale(element);\n }\n }\n const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);\n let x = (clientRect.left + visualOffsets.x) / scale.x;\n let y = (clientRect.top + visualOffsets.y) / scale.y;\n let width = clientRect.width / scale.x;\n let height = clientRect.height / scale.y;\n if (domElement) {\n const win = getWindow(domElement);\n const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;\n let currentIFrame = win.frameElement;\n while (currentIFrame && offsetParent && offsetWin !== win) {\n const iframeScale = getScale(currentIFrame);\n const iframeRect = currentIFrame.getBoundingClientRect();\n const css = getComputedStyle(currentIFrame);\n const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;\n const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;\n x *= iframeScale.x;\n y *= iframeScale.y;\n width *= iframeScale.x;\n height *= iframeScale.y;\n x += left;\n y += top;\n currentIFrame = getWindow(currentIFrame).frameElement;\n }\n }\n return rectToClientRect({\n width,\n height,\n x,\n y\n });\n}\nconst topLayerSelectors = [':popover-open', ':modal'];\nfunction topLayer(floating) {\n let isTopLayer = false;\n let x = 0;\n let y = 0;\n function setIsTopLayer(selector) {\n try {\n isTopLayer = isTopLayer || floating.matches(selector);\n } catch (e) {}\n }\n topLayerSelectors.forEach(selector => {\n setIsTopLayer(selector);\n });\n if (isTopLayer) {\n const containingBlock = getContainingBlock(floating);\n if (containingBlock) {\n const rect = containingBlock.getBoundingClientRect();\n x = rect.x;\n y = rect.y;\n }\n }\n return [isTopLayer, x, y];\n}\nfunction convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {\n let elements = _ref.elements,\n rect = _ref.rect,\n offsetParent = _ref.offsetParent,\n strategy = _ref.strategy;\n const documentElement = getDocumentElement(offsetParent);\n const _ref2 = elements ? topLayer(elements.floating) : [false],\n _ref3 = _slicedToArray(_ref2, 1),\n isTopLayer = _ref3[0];\n if (offsetParent === documentElement || isTopLayer) {\n return rect;\n }\n let scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n let scale = createCoords(1);\n const offsets = createCoords(0);\n const isOffsetParentAnElement = isHTMLElement(offsetParent);\n if (isOffsetParentAnElement || !isOffsetParentAnElement && strategy !== 'fixed') {\n if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n if (isHTMLElement(offsetParent)) {\n const offsetRect = getBoundingClientRect(offsetParent);\n scale = getScale(offsetParent);\n offsets.x = offsetRect.x + offsetParent.clientLeft;\n offsets.y = offsetRect.y + offsetParent.clientTop;\n }\n }\n return {\n width: rect.width * scale.x,\n height: rect.height * scale.y,\n x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x,\n y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y\n };\n}\nfunction getClientRects(element) {\n return Array.from(element.getClientRects());\n}\nfunction getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n return getBoundingClientRect(getDocumentElement(element)).left + getNodeScroll(element).scrollLeft;\n}\n\n// Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable.\nfunction getDocumentRect(element) {\n const html = getDocumentElement(element);\n const scroll = getNodeScroll(element);\n const body = element.ownerDocument.body;\n const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);\n const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);\n let x = -scroll.scrollLeft + getWindowScrollBarX(element);\n const y = -scroll.scrollTop;\n if (getComputedStyle(body).direction === 'rtl') {\n x += max(html.clientWidth, body.clientWidth) - width;\n }\n return {\n width,\n height,\n x,\n y\n };\n}\nfunction getViewportRect(element, strategy) {\n const win = getWindow(element);\n const html = getDocumentElement(element);\n const visualViewport = win.visualViewport;\n let width = html.clientWidth;\n let height = html.clientHeight;\n let x = 0;\n let y = 0;\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n const visualViewportBased = isWebKit();\n if (!visualViewportBased || visualViewportBased && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n return {\n width,\n height,\n x,\n y\n };\n}\n\n// Returns the inner client rect, subtracting scrollbars if present.\nfunction getInnerBoundingClientRect(element, strategy) {\n const clientRect = getBoundingClientRect(element, true, strategy === 'fixed');\n const top = clientRect.top + element.clientTop;\n const left = clientRect.left + element.clientLeft;\n const scale = isHTMLElement(element) ? getScale(element) : createCoords(1);\n const width = element.clientWidth * scale.x;\n const height = element.clientHeight * scale.y;\n const x = left * scale.x;\n const y = top * scale.y;\n return {\n width,\n height,\n x,\n y\n };\n}\nfunction getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {\n let rect;\n if (clippingAncestor === 'viewport') {\n rect = getViewportRect(element, strategy);\n } else if (clippingAncestor === 'document') {\n rect = getDocumentRect(getDocumentElement(element));\n } else if (isElement(clippingAncestor)) {\n rect = getInnerBoundingClientRect(clippingAncestor, strategy);\n } else {\n const visualOffsets = getVisualOffsets(element);\n rect = _objectSpread(_objectSpread({}, clippingAncestor), {}, {\n x: clippingAncestor.x - visualOffsets.x,\n y: clippingAncestor.y - visualOffsets.y\n });\n }\n return rectToClientRect(rect);\n}\nfunction hasFixedPositionAncestor(element, stopNode) {\n const parentNode = getParentNode(element);\n if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {\n return false;\n }\n return getComputedStyle(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);\n}\n\n// A \"clipping ancestor\" is an `overflow` element with the characteristic of\n// clipping (or hiding) child elements. This returns all clipping ancestors\n// of the given element up the tree.\nfunction getClippingElementAncestors(element, cache) {\n const cachedResult = cache.get(element);\n if (cachedResult) {\n return cachedResult;\n }\n let result = getOverflowAncestors(element, [], false).filter(el => isElement(el) && getNodeName(el) !== 'body');\n let currentContainingBlockComputedStyle = null;\n const elementIsFixed = getComputedStyle(element).position === 'fixed';\n let currentNode = elementIsFixed ? getParentNode(element) : element;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {\n const computedStyle = getComputedStyle(currentNode);\n const currentNodeIsContaining = isContainingBlock(currentNode);\n if (!currentNodeIsContaining && computedStyle.position === 'fixed') {\n currentContainingBlockComputedStyle = null;\n }\n const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && ['absolute', 'fixed'].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);\n if (shouldDropCurrentNode) {\n // Drop non-containing blocks.\n result = result.filter(ancestor => ancestor !== currentNode);\n } else {\n // Record last containing block for next iteration.\n currentContainingBlockComputedStyle = computedStyle;\n }\n currentNode = getParentNode(currentNode);\n }\n cache.set(element, result);\n return result;\n}\n\n// Gets the maximum area that the element is visible in due to any number of\n// clipping ancestors.\nfunction getClippingRect(_ref) {\n let element = _ref.element,\n boundary = _ref.boundary,\n rootBoundary = _ref.rootBoundary,\n strategy = _ref.strategy;\n const elementClippingAncestors = boundary === 'clippingAncestors' ? getClippingElementAncestors(element, this._c) : [].concat(boundary);\n const clippingAncestors = [...elementClippingAncestors, rootBoundary];\n const firstClippingAncestor = clippingAncestors[0];\n const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {\n const rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy));\n return {\n width: clippingRect.right - clippingRect.left,\n height: clippingRect.bottom - clippingRect.top,\n x: clippingRect.left,\n y: clippingRect.top\n };\n}\nfunction getDimensions(element) {\n const _getCssDimensions2 = getCssDimensions(element),\n width = _getCssDimensions2.width,\n height = _getCssDimensions2.height;\n return {\n width,\n height\n };\n}\nfunction getRectRelativeToOffsetParent(element, offsetParent, strategy, floating) {\n const isOffsetParentAnElement = isHTMLElement(offsetParent);\n const documentElement = getDocumentElement(offsetParent);\n const isFixed = strategy === 'fixed';\n const rect = getBoundingClientRect(element, true, isFixed, offsetParent);\n let scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n const offsets = createCoords(0);\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n if (isOffsetParentAnElement) {\n const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);\n offsets.x = offsetRect.x + offsetParent.clientLeft;\n offsets.y = offsetRect.y + offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n let x = rect.left + scroll.scrollLeft - offsets.x;\n let y = rect.top + scroll.scrollTop - offsets.y;\n const _topLayer = topLayer(floating),\n _topLayer2 = _slicedToArray(_topLayer, 3),\n isTopLayer = _topLayer2[0],\n topLayerX = _topLayer2[1],\n topLayerY = _topLayer2[2];\n if (isTopLayer) {\n x += topLayerX;\n y += topLayerY;\n if (isOffsetParentAnElement) {\n x += offsetParent.clientLeft;\n y += offsetParent.clientTop;\n }\n }\n return {\n x,\n y,\n width: rect.width,\n height: rect.height\n };\n}\nfunction getTrueOffsetParent(element, polyfill) {\n if (!isHTMLElement(element) || getComputedStyle(element).position === 'fixed') {\n return null;\n }\n if (polyfill) {\n return polyfill(element);\n }\n return element.offsetParent;\n}\n\n// Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\nfunction getOffsetParent(element, polyfill) {\n const window = getWindow(element);\n if (!isHTMLElement(element)) {\n return window;\n }\n let offsetParent = getTrueOffsetParent(element, polyfill);\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent, polyfill);\n }\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static' && !isContainingBlock(offsetParent))) {\n return window;\n }\n return offsetParent || getContainingBlock(element) || window;\n}\nconst getElementRects = async function (data) {\n const getOffsetParentFn = this.getOffsetParent || getOffsetParent;\n const getDimensionsFn = this.getDimensions;\n return {\n reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy, data.floating),\n floating: _objectSpread({\n x: 0,\n y: 0\n }, await getDimensionsFn(data.floating))\n };\n};\nfunction isRTL(element) {\n return getComputedStyle(element).direction === 'rtl';\n}\nconst platform = {\n convertOffsetParentRelativeRectToViewportRelativeRect,\n getDocumentElement,\n getClippingRect,\n getOffsetParent,\n getElementRects,\n getClientRects,\n getDimensions,\n getScale,\n isElement,\n isRTL\n};\n\n// https://samthor.au/2021/observing-dom/\nfunction observeMove(element, onMove) {\n let io = null;\n let timeoutId;\n const root = getDocumentElement(element);\n function cleanup() {\n var _io;\n clearTimeout(timeoutId);\n (_io = io) == null || _io.disconnect();\n io = null;\n }\n function refresh(skip, threshold) {\n if (skip === void 0) {\n skip = false;\n }\n if (threshold === void 0) {\n threshold = 1;\n }\n cleanup();\n const _element$getBoundingC = element.getBoundingClientRect(),\n left = _element$getBoundingC.left,\n top = _element$getBoundingC.top,\n width = _element$getBoundingC.width,\n height = _element$getBoundingC.height;\n if (!skip) {\n onMove();\n }\n if (!width || !height) {\n return;\n }\n const insetTop = floor(top);\n const insetRight = floor(root.clientWidth - (left + width));\n const insetBottom = floor(root.clientHeight - (top + height));\n const insetLeft = floor(left);\n const rootMargin = -insetTop + \"px \" + -insetRight + \"px \" + -insetBottom + \"px \" + -insetLeft + \"px\";\n const options = {\n rootMargin,\n threshold: max(0, min(1, threshold)) || 1\n };\n let isFirstUpdate = true;\n function handleObserve(entries) {\n const ratio = entries[0].intersectionRatio;\n if (ratio !== threshold) {\n if (!isFirstUpdate) {\n return refresh();\n }\n if (!ratio) {\n timeoutId = setTimeout(() => {\n refresh(false, 1e-7);\n }, 100);\n } else {\n refresh(false, ratio);\n }\n }\n isFirstUpdate = false;\n }\n\n // Older browsers don't support a `document` as the root and will throw an\n // error.\n try {\n io = new IntersectionObserver(handleObserve, _objectSpread(_objectSpread({}, options), {}, {\n // Handle