\r\n )}\r\n\r\n {add && (\r\n \r\n )}\r\n >\r\n }\r\n actions={noActionsColumn ? customActionsWithoutColumn : actions}\r\n titleName={title}\r\n options={{\r\n filtering,\r\n selection,\r\n selectionProps,\r\n showSelectAllCheckbox,\r\n exportAllData: true,\r\n search: filterable,\r\n exportButton: !noExport && { csv: true, pdf: true },\r\n headerStyle: {\r\n position: 'sticky',\r\n top: 0,\r\n },\r\n cellStyle: { textAlign: 'left', wordWrap: 'break-word' },\r\n columnsButton: !noColumnsButton,\r\n resetColumnsButton: !noColumnsButton,\r\n maxBodyHeight,\r\n exportFileName: `${title}_Table_Export`,\r\n paging: true,\r\n addRowPosition: 'first',\r\n grouping,\r\n actionsColumnIndex: -1,\r\n pageSizeOptions: [50, 100, 250, 500],\r\n toolbarButtonAlignment,\r\n pageSize: 50,\r\n searchAutoFocus: false,\r\n showTextRowsSelected: false,\r\n emptyRowsWhenPaging: false,\r\n }}\r\n addActionRef={addActionRef}\r\n state={{\r\n columns: columns || transformColumns || loadingColumns,\r\n data: data || state?.data,\r\n }}\r\n editable={editable}\r\n parentChildData={parentChildData}\r\n remoteData={remoteData}\r\n tableRef={tableRef}\r\n detailPanel={detailPanel}\r\n overrideOnRowSelected={overrideOnRowSelected}\r\n defaultColumns={defaultColumns}\r\n />\r\n >\r\n );\r\n}\r\n","/* eslint-disable react-refresh/only-export-components */\r\nimport { useEffect, useMemo } from 'react';\r\nimport { useSelector, useDispatch } from 'react-redux';\r\nimport store from '../../store/store';\r\n\r\nimport Table, { loadingColumnsConstructor } from './ReduxTable';\r\nimport { axios } from '../../services/axios';\r\nimport { Error, EditForm, Modal } from '..';\r\n\r\n// A search function exported and used by only a few tables in the app\r\nexport const floatSearch = (v, rowData, field) => {\r\n return Math.abs(parseFloat(v) - rowData[field]) < Number.EPSILON;\r\n};\r\n\r\n// a custom function to create the title of the modal when clicking on a table entry\r\nexport const modalTitle = (data, attribute, section, mode) => {\r\n if (data !== null && data[attribute]) {\r\n return mode + section + ' : ' + data[attribute];\r\n }\r\n return mode + section;\r\n};\r\n\r\n// A function to dispatch the error in the modal to the state\r\nexport const onModalError = (e) => {\r\n store.dispatch({\r\n type: 'CHANGE_MODAL_BACKEND_ERROR',\r\n payload: e,\r\n });\r\n};\r\n\r\n/*\r\n * Table And Modal Function that takes in a series of props\r\n * This component is reponsible for fetching table data and displaying it as listed by the ReduxTable.jsx\r\n * This compoent is responsible for passing through data that is fetched to the modal so when a user clicks on a entry ->\r\n * The entry opens in a modal with all the required data that the entry has in the database\r\n * ReduxTable and ReduxModal are the two components that this uses to render those pages\r\n */\r\nexport default function TableAndModal(props) {\r\n const {\r\n // defaultColumns is used to set the columns for the table\r\n defaultColumns,\r\n // tableFetch is the url for the api to perform a get request to\r\n tableFetch,\r\n // onTableFetch is triggered when the fetch is performed\r\n onTableFetch,\r\n // onModalSucceed is used to trigger somethin when the modal request(whatever it is) returns a 200 - ie redirect to edit after add is successfull\r\n onModalSucceed,\r\n // overrideModalAdd is used to override the method for the add request of the modal\r\n overrideModalAdd,\r\n // overrideModalUpdate is used to override the method for the edit reuqest of the modal\r\n overrideModalUpdate,\r\n // onModalCopy is something that triggers after the 'Copy' functionality returns successfully\r\n onModalCopy,\r\n // overrideTableLoading overrides the loading method for the table\r\n overrideTableLoading,\r\n // modalFetch is the URL for the get request when you click the edit button on any of the tables\r\n modalFetch,\r\n // I am not sure what this does but it seems to take a series of 3 different data sets\r\n modalUpload,\r\n // onModalUpdate is a function that is triggered when the modalUpdate is sucessful\r\n onModalUpdate,\r\n // overrideOnModalError is a way to override the default error handling process of this component\r\n onModalError: overrideOnModalError,\r\n // modalAdd is the URL for the add option of a modal\r\n modalAdd,\r\n // modalConvert is the URL for the convert option of a modal\r\n modalConvert,\r\n // modalDelete is the URL for the delete option for a modal\r\n modalDelete,\r\n // modalUpdate is the URL for the put request when updating any entity that you have opened in a modal\r\n modalUpdate,\r\n // modalApproval is the URL for any reuqests made to approve a company using a modal\r\n modalApproval,\r\n // modalCopy is the URL for any requests made to modals using the copy mode\r\n modalCopy,\r\n // onModalAdd is a function that happens after a post request is sucessful, like redirecting to the edit page once a trunk is created\r\n onModalAdd,\r\n // the validation logic for a modal, it is presented as a combined error state for whatever is listed. Easier to understand looking a trunks.jsx\r\n modalValidate,\r\n // determines if the edit icon is shown in the table, bool\r\n editable,\r\n // I do not know what this does and have never seen it\r\n onModalChangeLogo,\r\n // If you want to pass static data to the table instead of fetching data this prop is used for that\r\n data,\r\n // determines if the modal will be a full page or if it wil be a pop up -> true is full page\r\n newPage,\r\n // Determines whether there is a alphabet based filter field on the Table component\r\n alphabetFilterField,\r\n // a way to override table rows actions for the Table - If you would like to have anything specific that isnt a option below\r\n rowActions: tableRowActions,\r\n // onTableSucceed is a method that is called once the table has successfully loaded\r\n onTableSucceed,\r\n // Set to true if implementing custom actions column\r\n noActionsColumn,\r\n } = props;\r\n\r\n // tableloading and error state\r\n const { loading: tableLoading, error } = useSelector((state) => {\r\n return { ...state.table };\r\n });\r\n\r\n // State of the modal destructured into many variables\r\n // TODO: Figure out what modalFreshData is, most likely something to do with the state hashing to stop leaving a page with unsaved changes\r\n const {\r\n loading: modalLoading,\r\n state: modalState,\r\n mode: modalMode,\r\n uploading: modalUploading,\r\n freshData: modalFreshData,\r\n show: modalShow,\r\n data: modalData,\r\n } = useSelector((state) => {\r\n return {\r\n ...state.modal,\r\n };\r\n });\r\n\r\n const dispatch = useDispatch();\r\n\r\n /*\r\n * Initial Table loading and fetching logic\r\n * if data and overrideTableLoading are not specificied AND tableLoading ->\r\n * Either make a fetch request of onTableFetch or axios.get with the tableFetch url passed in from props\r\n */\r\n useEffect(() => {\r\n if (!(data || overrideTableLoading) && tableLoading) {\r\n const fetchRequest = onTableFetch\r\n ? onTableFetch()\r\n : axios.get(tableFetch);\r\n fetchRequest\r\n .then((res) => {\r\n dispatch({\r\n type: 'CHANGE_TABLE_STATE',\r\n payload: {\r\n //transform data when data is fetched using default columns and onTableSuceed prop if its passsed in\r\n columns: defaultColumns,\r\n data: onTableSucceed\r\n ? onTableSucceed(res.data)\r\n : res.data,\r\n },\r\n });\r\n //custom sort by alphabet functionality only used once\r\n if (alphabetFilterField) {\r\n dispatch({ type: 'CHANGE_TABLE_INDEXING' });\r\n }\r\n dispatch({ type: 'CHANGE_TABLE_LOADING' });\r\n })\r\n .catch((e) => {\r\n if (e.response?.status !== 401) {\r\n dispatch({\r\n type: 'CHANGE_TABLE_ERROR',\r\n payload: e,\r\n });\r\n } else {\r\n dispatch({ type: 'CHANGE_TABLE_LOADING' });\r\n }\r\n });\r\n }\r\n }, [tableLoading]);\r\n\r\n /*\r\n * Loading of modal data if modalShow, modalLoading and modalFetch exist\r\n * modalFetch is used for axios request, this result is then dispatched to the modal State\r\n * loading and hash are then dispatched, else no modal is loaded\r\n */\r\n useEffect(() => {\r\n if (modalShow && modalLoading && modalFetch) {\r\n axios\r\n .get(modalFetch)\r\n .then((res) => {\r\n dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n ...res.data,\r\n },\r\n });\r\n dispatch({ type: 'CHANGE_MODAL_LOADING', payload: false });\r\n dispatch({\r\n type: 'CHANGE_MODAL_HASH',\r\n });\r\n })\r\n .catch((e) => {\r\n onModalError(e);\r\n });\r\n } else if (modalShow && modalLoading && !modalFetch) {\r\n dispatch({ type: 'CHANGE_MODAL_LOADING', payload: false });\r\n dispatch({\r\n type: 'CHANGE_MODAL_HASH',\r\n });\r\n }\r\n }, [modalLoading, modalShow]);\r\n\r\n /*\r\n * A function to determine what tableRow actions to show based on either its a Add or Edit modal\r\n * tableRowActions are determined and based on some factors I don't understand a breadcrumb view is added\r\n * Breadcrumb view shows where the modal came from and some information around it in the title\r\n */\r\n const onSucceed = (res) => {\r\n if (modalMode === 'Add') {\r\n if (tableRowActions?.multiChildTable) {\r\n dispatch({\r\n type: 'OPEN_CHILD_TABLE',\r\n payload: { ...res.data, append: true },\r\n });\r\n dispatch({\r\n type: 'CHANGE_BREADCRUMB_VIEW',\r\n payload: tableRowActions?.multiChildTable?.to ?? 0,\r\n });\r\n dispatch({\r\n type: 'RESET_MODAL',\r\n });\r\n return;\r\n }\r\n if (\r\n tableRowActions?.childTable &&\r\n !tableRowActions?.childTable?.doNotOverrideOnModalSucceed\r\n ) {\r\n dispatch({\r\n type: 'OPEN_CHILD_TABLE',\r\n payload: { ...res.data, append: true },\r\n });\r\n dispatch({\r\n type: 'RESET_MODAL',\r\n });\r\n return;\r\n }\r\n }\r\n //this is how the table is loaded by default\r\n dispatch({\r\n type: 'ON_MODAL_SUBMIT_SUCCEED',\r\n });\r\n // change the table loading state\r\n dispatch({\r\n type: 'CHANGE_TABLE_LOADING',\r\n });\r\n // load the colums and data into the table state\r\n // dispatch({\r\n // type: 'CHANGE_TABLE_STATE',\r\n // payload: {columns: loadingColumns, data: loadingData},\r\n // });\r\n };\r\n\r\n /*\r\n * This fucntion determines what data you want to submit\r\n * And it also determins how you want to submit it\r\n */\r\n useEffect(() => {\r\n // whenever the modal is uploading, this effect checks what type the mode is and acts accordingly\r\n if (modalUploading) {\r\n var axiosResponse = null;\r\n switch (modalMode) {\r\n // change logo case: if validation happens and its false, return a error.\r\n // Otherwise use the provided axios endpoint\r\n case 'Change Logo':\r\n if (\r\n modalValidate && // need to do validation\r\n !modalValidate() //validation return false\r\n ) {\r\n onModalError({\r\n name: 'Field Error',\r\n message: 'There are some field errors.',\r\n });\r\n return;\r\n }\r\n axiosResponse = onModalChangeLogo();\r\n break;\r\n // delete case: return a delte response with the modalDelete url\r\n // not sure what the modalFreshData stuff means.\r\n case 'Delete':\r\n axiosResponse = axios.delete(\r\n modalDelete,\r\n modalUpload(modalFreshData || modalData, modalState),\r\n modalUpload(modalFreshData || modalData, modalState)\r\n .config,\r\n );\r\n\r\n break;\r\n // add case: if validation happens and it false, dispatch error.\r\n // else return either modalAdd url, overrideModalAdd or onModalAdd\r\n case 'Add':\r\n if (\r\n modalValidate && // need to do validation\r\n !modalValidate() //validation return false\r\n ) {\r\n onModalError({\r\n name: 'Field Error',\r\n message: 'There are some field errors.',\r\n });\r\n return;\r\n }\r\n\r\n if (modalAdd) {\r\n axiosResponse = axios.post(\r\n modalAdd,\r\n modalUpload(\r\n modalFreshData || modalData,\r\n modalState,\r\n ),\r\n );\r\n } else if (onModalAdd) {\r\n axiosResponse = onModalAdd();\r\n } else {\r\n overrideModalAdd();\r\n return;\r\n }\r\n break;\r\n // approval case: return the modalApproval URl\r\n case 'Approval':\r\n axiosResponse = axios.put(\r\n modalApproval,\r\n modalUpload(modalFreshData || modalData, modalState),\r\n );\r\n break;\r\n // convert case: return the modalConvert URL\r\n case 'Convert':\r\n axiosResponse = axios.post(\r\n modalConvert,\r\n modalUpload(modalFreshData || modalData),\r\n );\r\n break;\r\n // edit case: if validation is requred and is false, dispatch a error\r\n // else return modalUpdate, onModalUpdate or overrideModalUpdate based on props\r\n case 'Edit':\r\n if (\r\n modalValidate && // need to do validation\r\n !modalValidate() //validation return false\r\n ) {\r\n onModalError({\r\n name: 'Field Error',\r\n message: 'There are some field errors.',\r\n });\r\n return;\r\n }\r\n if (modalUpdate) {\r\n axiosResponse = axios.put(\r\n modalUpdate,\r\n modalUpload(\r\n modalFreshData || modalData,\r\n modalState,\r\n ),\r\n modalUpload(modalFreshData || modalData, modalState)\r\n ?.config,\r\n );\r\n } else if (onModalUpdate) {\r\n axiosResponse = onModalUpdate();\r\n } else {\r\n overrideModalUpdate();\r\n return;\r\n }\r\n break;\r\n // copy case: if validation is required and its false then dispatch a error\r\n // else if return onModalCopy, else post with modalCopy\r\n case 'Copy':\r\n if (\r\n modalValidate && // need to do validation\r\n !modalValidate() //validation return false\r\n ) {\r\n onModalError({\r\n name: 'Field Error',\r\n message: 'There are some field errors.',\r\n });\r\n return;\r\n }\r\n if (onModalCopy) {\r\n onModalCopy();\r\n return;\r\n }\r\n\r\n // modal Copy Logic\r\n // not really sure what this is doing or why its neccessary for the app as redux actions are confusing\r\n axios\r\n .post(modalCopy)\r\n .then((copyResult) => {\r\n axios\r\n .put(modalUpdate, {\r\n ...copyResult.data,\r\n name: modalState?.copyName,\r\n })\r\n .then((renameResult) => {\r\n dispatch({\r\n type: 'OPEN_CHILD_TABLE',\r\n payload: {\r\n ...(renameResult?.data ?? {}),\r\n append: true,\r\n },\r\n });\r\n dispatch({\r\n type: 'CHANGE_BREADCRUMB_VIEW',\r\n payload:\r\n tableRowActions?.multiChildTable\r\n ?.to ?? 0,\r\n });\r\n return;\r\n })\r\n .catch((e2) => {\r\n dispatch({\r\n type: 'OPEN_CHILD_TABLE',\r\n payload: {\r\n ...(copyResult?.data ?? {}),\r\n append: true,\r\n },\r\n });\r\n dispatch({\r\n type: 'CHANGE_BREADCRUMB_VIEW',\r\n payload:\r\n tableRowActions?.multiChildTable\r\n ?.to ?? 0,\r\n });\r\n onModalError(e2);\r\n });\r\n })\r\n .catch((e) => {\r\n onModalError(e);\r\n });\r\n return;\r\n default:\r\n break;\r\n }\r\n\r\n /*\r\n * if there is a axios respoonse after all the above conditions, this executes it\r\n * the hash is changed using a dispatch\r\n * if onModalSuceed is inpt then it is called, else onSucceed is called\r\n * This block also has error handling\r\n */\r\n if (axiosResponse) {\r\n axiosResponse\r\n .then((res) => {\r\n dispatch({\r\n type: 'CHANGE_MODAL_HASH',\r\n });\r\n if (onModalSucceed) {\r\n onModalSucceed(res);\r\n return;\r\n }\r\n onSucceed(res);\r\n })\r\n .catch((e) => {\r\n if (overrideOnModalError) {\r\n overrideOnModalError(e);\r\n return;\r\n }\r\n onModalError(e);\r\n });\r\n }\r\n }\r\n }, [modalUploading]);\r\n\r\n //Memo that changes the columns the app renders when default columns changes\r\n const loadingColumns = useMemo(\r\n () => loadingColumnsConstructor(defaultColumns),\r\n [defaultColumns],\r\n );\r\n\r\n /*\r\n * The way the component renders all the data\r\n * If there is a error then the error compoent is returned\r\n * If the mode is either edit or add then the EditForm componet is rendered\r\n * else the Table and Modal is rendered\r\n */\r\n if (error) {\r\n return (\r\n <>\r\n \r\n >\r\n );\r\n }\r\n\r\n if (modalShow && newPage && (modalMode === 'Edit' || modalMode === 'Add')) {\r\n return ;\r\n }\r\n\r\n return (\r\n <>\r\n
\r\n \r\n >\r\n );\r\n}\r\n","import MultiSelect from './MultiselectSearchbox';\r\nimport { onModalError } from '../tables/TableAndModal';\r\n\r\n/*\r\n * A multiselect variant that remembers the input its hovered overed and then when clicking ->\r\n * Adds the option to the multiselect that is being focussed\r\n */\r\nconst FillOnClickMultiselect = ({\r\n staticEnum,\r\n activeTextareaID,\r\n activeTextareaField,\r\n setState,\r\n label,\r\n cursorPosition,\r\n setCursorPosition,\r\n ...rest\r\n}) => {\r\n function handleBtn(value) {\r\n const inputSelected = document.getElementById(activeTextareaID);\r\n if (inputSelected) {\r\n const textValue =\r\n inputSelected.value.substring(0, cursorPosition) +\r\n value +\r\n inputSelected.value.substring(\r\n cursorPosition,\r\n inputSelected.value.length,\r\n );\r\n setState({ [activeTextareaField]: textValue });\r\n inputSelected.value = textValue;\r\n inputSelected.focus();\r\n inputSelected.setSelectionRange(\r\n cursorPosition + value.length,\r\n cursorPosition + value.length,\r\n );\r\n setCursorPosition(inputSelected.selectionStart);\r\n }\r\n }\r\n\r\n return (\r\n {}}\r\n chip={{\r\n clickable: true,\r\n onClick: (e, option) => {\r\n handleBtn(option.id);\r\n },\r\n }}\r\n />\r\n );\r\n};\r\n\r\nexport default FillOnClickMultiselect;\r\n","import {useEffect, useState} from 'react';\r\n\r\nexport default function useDetectFileType(file) {\r\n const [fileType, setFileType] = useState(null);\r\n\r\n useEffect(() => {\r\n if (!file || !file.includes) return;\r\n const isPng = file.includes('.PNG') || file.includes('.png');\r\n const isSvg = file.includes('.SVG') || file.includes('.svg');\r\n const isBase64Svg = file.includes('data:image/svg');\r\n const isBase64Png = file.includes('data:image/png');\r\n\r\n if (isPng || isBase64Png) setFileType('png');\r\n if (isSvg || isBase64Svg) setFileType('svg');\r\n }, [file]);\r\n\r\n return fileType;\r\n}\r\n","import { useSelector } from 'react-redux';\r\nimport { Helmet } from 'react-helmet';\r\nimport useDetectFileType from 'hooks/useDetectFileType';\r\n\r\n/*\r\n * Header component to get favicon and company name from state\r\n */\r\nconst Header = () => {\r\n // const dispatch = useDispatch();\r\n\r\n const { partnerName, favIconPath } = useSelector((state) => {\r\n return { ...state.header };\r\n });\r\n\r\n const imgFileType = useDetectFileType(favIconPath);\r\n\r\n // useEffect(() => {\r\n // if (!partnerName || !favIconPath) {\r\n // axios.get(`/theme/${window.location.host}`).then((res) => {\r\n // const { data } = res;\r\n // dispatch({\r\n // type: 'SET_SBC_DOMAIN',\r\n // payload: data.sbcDomain,\r\n // });\r\n // dispatch({\r\n // type: 'CHANGE_IMAGE_PATH_LIGHT_MODE',\r\n // payload: data.lightLogo,\r\n // });\r\n // dispatch({\r\n // type: 'CHANGE_IMAGE_PATH_DARK_MODE',\r\n // payload: data.darkLogo,\r\n // });\r\n\r\n // dispatch({\r\n // type: 'HEADER_FAVICON_SUCCESS',\r\n // payload: data.favicon,\r\n // });\r\n // dispatch({\r\n // type: 'HEADER_TITLE_SUCCESS',\r\n // payload: data.titleName,\r\n // });\r\n // dispatch({\r\n // type: 'SET_SUPPORT_URL',\r\n // payload: data.extLinkSupport,\r\n // });\r\n // });\r\n // }\r\n // }, [partnerName, favIconPath]);\r\n\r\n //returns helmet with image and partner name\r\n return (\r\n \r\n {/**\r\n * @note CSP frame-ancestors\r\n * @see https://content-security-policy.com/frame-ancestors/\r\n */}\r\n \r\n \r\n {partnerName}\r\n \r\n );\r\n};\r\n\r\nexport default Header;\r\n","import React, { useState } from 'react';\r\nimport { useSelector } from 'react-redux';\r\nimport TextField from '@material-ui/core/TextField';\r\nimport Autocomplete from '@material-ui/lab/Autocomplete';\r\nimport { Spinner, Box } from '@chakra-ui/react';\r\nimport { ChevronDownIcon, QuestionOutlineIcon } from '@chakra-ui/icons';\r\n\r\nimport config from '../../config.json';\r\nimport ErrorBoundary from '../maintenance/ErrorBoundary';\r\nimport { customAutoCompleteStyle } from 'pages/navbar/constant';\r\nimport { InputAdornment, Tooltip } from '@material-ui/core';\r\n\r\nexport const findCurrentValue = ({\r\n options,\r\n displayField,\r\n dropDownValue,\r\n currentValue,\r\n noneFieldDisplay,\r\n onDisplayDropdown,\r\n}) => {\r\n if (!options || !displayField || !dropDownValue) {\r\n return null;\r\n }\r\n var res = options?.find((v) => {\r\n return v[dropDownValue] === currentValue;\r\n });\r\n\r\n if (!res) {\r\n return noneFieldDisplay || config.notAllocated.dropdown;\r\n }\r\n return (\r\n (onDisplayDropdown && onDisplayDropdown(res)) ||\r\n res[displayField] ||\r\n res ||\r\n 'ERROR:Not Found!!!!'\r\n );\r\n};\r\n\r\n// Specific for 'Company Managing' field on drop down\r\n// Labels company and partner for group by function of autocomplete\r\nexport const relabel = (companies) => {\r\n var res = [];\r\n let parentName = '';\r\n let parentID = '';\r\n for (const company of companies) {\r\n if (company.parent == null || company.parent.length === 0) {\r\n parentName = company.name;\r\n parentID = company.id;\r\n res.push({\r\n id: company.id,\r\n name: company.name,\r\n parentID: '',\r\n parentName: '',\r\n });\r\n } else {\r\n res.push({\r\n id: company.id,\r\n name: company.name,\r\n parentID,\r\n parentName,\r\n });\r\n }\r\n }\r\n return res;\r\n};\r\n\r\nexport const groupBy = (option) => {\r\n if (option.parentName.length === 0) {\r\n return option.name;\r\n }\r\n return option.parentName;\r\n};\r\n\r\nconst getOptionSelectedID = (option, v) => {\r\n return option.id === v.id;\r\n};\r\n\r\nexport const getOptionSelected = (option, value) => {\r\n if (typeof value === 'string') {\r\n return value === option.id;\r\n }\r\n return option.name === value.name;\r\n};\r\n\r\nexport const getOptionLabel = (option) => option.name || '';\r\n\r\n/*\r\n * SearchBox component used by multi selects, auto completes and drop downs that require search functionality\r\n */\r\nexport default function Asynchronous(props) {\r\n const { colorScheme } = useSelector((state) => state.settings);\r\n const [open, setOpen] = useState(false);\r\n const {\r\n placeholder,\r\n defaultValue,\r\n loading,\r\n onChange,\r\n message,\r\n onFocus,\r\n label,\r\n displayField,\r\n dropDownValue,\r\n onDisplayDropdown,\r\n options,\r\n noneFieldDisplay,\r\n helperText,\r\n errorText,\r\n groupByProps,\r\n endAdornment,\r\n renderOption,\r\n getOptionSelected: getOptionSelectedProps,\r\n getOptionLabel: getOptionLabelProps,\r\n dataWalkthroughid,\r\n isRequired = false,\r\n hasTooltip = false,\r\n tooltipLabel = 'Field is required.',\r\n } = props;\r\n\r\n const findCurrentName = () => {\r\n var res = options.find((v) => {\r\n return v.id === defaultValue;\r\n });\r\n var name = res?.name;\r\n if (res?.parentName) {\r\n name = res?.name + ' Under: ' + res?.parentName;\r\n }\r\n return name;\r\n };\r\n\r\n const [isHovered, setIsHovered] = useState(false);\r\n\r\n // For each option you pass in, it must not be null, hence the error boundary\r\n return (\r\n \r\n \r\n {\r\n //ASSUMPTION :ONLY USED WHEN THERE'S GROUP BY?\r\n if (value != null) {\r\n //CHANGE!\r\n const foundItem = options.filter(\r\n (company) =>\r\n company?.[dropDownValue ?? 'id'] ===\r\n value?.[dropDownValue ?? 'id'],\r\n );\r\n onChange(foundItem[0]);\r\n }\r\n }}\r\n onOpen={() => {\r\n setOpen(true);\r\n }}\r\n onClose={() => {\r\n setOpen(false);\r\n }}\r\n groupBy={groupByProps}\r\n getOptionSelected={\r\n getOptionSelectedProps || getOptionSelectedID\r\n }\r\n getOptionLabel={getOptionLabelProps || getOptionLabel}\r\n options={options}\r\n loading={loading}\r\n disableClearable\r\n renderInput={(params) => {\r\n return (\r\n setIsHovered(true)}\r\n onMouseLeave={() => setIsHovered(false)}\r\n placeholder={\r\n placeholder ||\r\n findCurrentValue({\r\n options,\r\n displayField,\r\n dropDownValue,\r\n currentValue: defaultValue,\r\n message,\r\n onDisplayDropdown,\r\n noneFieldDisplay,\r\n }) ||\r\n findCurrentName()\r\n }\r\n variant=\"outlined\"\r\n size=\"small\"\r\n InputProps={{\r\n ...params.InputProps,\r\n endAdornment: (\r\n \r\n {loading ? (\r\n \r\n ) : null}\r\n {endAdornment}\r\n {params.InputProps.endAdornment}\r\n {isHovered && hasTooltip && (\r\n \r\n \r\n \r\n \r\n \r\n )}\r\n \r\n ),\r\n }}\r\n InputLabelProps={{ shrink: true }}\r\n />\r\n );\r\n }}\r\n popupIcon={}\r\n />\r\n \r\n \r\n );\r\n}\r\n","/* eslint-disable no-unused-vars */\r\nimport React, { useState, useEffect, forwardRef } from 'react';\r\nimport Skeleton from '@material-ui/lab/Skeleton';\r\nimport { MenuItem, FormControl, TextField } from '@material-ui/core';\r\nimport { useSelector } from 'react-redux';\r\nimport { Box } from '@chakra-ui/react';\r\nimport { ChevronDownIcon } from '@chakra-ui/icons';\r\n\r\nimport { axios } from '../../services/axios';\r\nimport Searchbox from '../presentational/Searchbox.jsx';\r\nimport config from '../../config.json';\r\nimport { customAutoCompleteStyle } from 'pages/navbar/constant';\r\n\r\n// eslint-disable-next-line react/display-name\r\nconst CustomChevronDownIcon = forwardRef((props, ref) => (\r\n \r\n));\r\n\r\n/*\r\n * Component used for drop down fields in the UI that require a series of options\r\n * those options can be gathered from a static list, fetched from the API when the component renders etc\r\n * This component also changes state so that modal forms can submit data using the value from the drop down\r\n */\r\nconst LoadingFieldDropdown = ({\r\n // this prop stops the component from fetching until another field/value has data\r\n dependency,\r\n // if there is no field display or we want a different default display then this value is shown\r\n noneFieldDisplay,\r\n // determines when the data will be fetched, if init is true it will be fetched when its loaded\r\n init,\r\n // function that triggers when the display drop down is shown\r\n onDisplayDropdown,\r\n // value behind the noneFieldDisplay as all values have a different display\r\n noneFieldValue,\r\n // prop to determine if its not a modal component\r\n notModalComponent,\r\n // instead of a api fetch the component can be fed a static list to use\r\n staticEnum,\r\n // the onChange function to be passed into the material component of this\r\n onChange,\r\n //\r\n noneField,\r\n // a function that can be passed in to represent a error, usually the onError from TableAndModal.jsx\r\n onError,\r\n // prop to pass through to sub componennts\r\n toggleLimit,\r\n // prop to pass through to sub componennts\r\n loadDependencies,\r\n // boolean to determine whether its searchable or not\r\n searchable,\r\n // the URL for fetching the data to populate the list\r\n fieldFetch,\r\n // label for the component as its a MUI textfield/searchbox\r\n fieldName,\r\n // used to determine the type of the value in the drop down, strint, int, bool etc\r\n fieldValue,\r\n // the value that is used for the state setting when selecting a value\r\n dropDownValue,\r\n // the field that is actually displayed in the drop down\r\n displayField,\r\n // props for the drop down list\r\n dropdownProps,\r\n // makes it so there is no empty option when the field first loads the drop down data\r\n noEmptyOption,\r\n // a function that triggers when the fetch is sucessful\r\n onFieldFetch,\r\n // determins if the component has dependencies\r\n hasDependency,\r\n // additional options for the static array that is passed into this component\r\n additional,\r\n // helper text is set inside the drop down\r\n helperText,\r\n // error text is what is displayed if there is a modalError\r\n errorText,\r\n // a bool that disalbes the drop down\r\n disabled,\r\n // a value to group the results of the api call or static enum by\r\n groupBy,\r\n // funciton that triggers when the funciton is focussed on\r\n onFocus,\r\n // if you want to render whats inside the wrapper as something that isnt a searchbox/textfield\r\n renderOption,\r\n // a filter for the options of the search box\r\n filter,\r\n // icon or any other sort of adornment that goes at the end of the field\r\n endAdornment,\r\n dataWalkthroughid, // used for the walkthrough\r\n isRequired, // show asterick beside label\r\n hasTooltip, // show tooltip on the right end\r\n tooltipLabel, // custom title for tooltip\r\n ...rest\r\n}) => {\r\n const [enumArray, setEnum] = useState(staticEnum || []);\r\n const [enumLoading, setEnumLoading] = useState(false);\r\n\r\n // state to detemine if the modal is showing\r\n const { show: modalShow } = useSelector((state) => {\r\n return { ...state.modal };\r\n });\r\n const { colorScheme } = useSelector((state) => state.settings);\r\n\r\n /*\r\n * Fetch function for the results based with onFieldFetch, fieldFetch props\r\n * if this is sucsessful the enum state is set to the result\r\n */\r\n const fetch = () => {\r\n setEnumLoading(true);\r\n if (onFieldFetch) {\r\n onFieldFetch()\r\n .then((res) => {\r\n setEnum(res.data);\r\n setEnumLoading(false);\r\n })\r\n .catch((e) => {\r\n onError(e);\r\n setEnumLoading(false);\r\n });\r\n return;\r\n }\r\n axios\r\n .get(fieldFetch)\r\n .then((res) => {\r\n setEnum(res.data);\r\n setEnumLoading(false);\r\n })\r\n .catch((e) => {\r\n onError(e);\r\n setEnumLoading(false);\r\n });\r\n };\r\n\r\n /*\r\n * Function to extract the field value\r\n * checks the type of this value and returns the fieldvalue\r\n */\r\n const extractFieldValue = () => {\r\n //set default case\r\n switch (typeof fieldValue) {\r\n case 'object':\r\n return fieldValue || '';\r\n case 'string':\r\n return fieldValue || '';\r\n case 'number':\r\n return fieldValue;\r\n default:\r\n return fieldValue;\r\n }\r\n };\r\n\r\n /*\r\n * calls a fetch based onFieldFetch or fieldFetch existing\r\n * also requires static enum and dependency to be false\r\n * also requires init or modalShow or notModalComponent to execuse fetch()\r\n */\r\n useEffect(() => {\r\n if (\r\n (onFieldFetch || fieldFetch) &&\r\n !staticEnum && //not static\r\n !hasDependency && // not depending on sth else\r\n (init || //do at first place\r\n modalShow)\r\n ) {\r\n fetch();\r\n }\r\n }, [modalShow, staticEnum]);\r\n\r\n /*\r\n * fetches based on the same factors as abovem doesnt accoutn for init or modalShow\r\n * could most likley be refacorted into a single useEffect()\r\n */\r\n useEffect(() => {\r\n if ((onFieldFetch || fieldFetch) && !staticEnum && hasDependency) {\r\n fetch();\r\n }\r\n }, [hasDependency, dependency, staticEnum]);\r\n\r\n /*\r\n * If the enumLoading state is true, returns a skeleton component\r\n */\r\n if (enumLoading) {\r\n return ;\r\n }\r\n\r\n /*\r\n * If the serachable prop is entered with a static enum of length > 0 then render a search box\r\n * many props are used for material ui requirements for SearchBox, documentation is online for those props\r\n */\r\n if (\r\n searchable &&\r\n !disabled &&\r\n (staticEnum || enumArray)?.concat(additional || []).length > 0\r\n ) {\r\n return (\r\n {\r\n onChange(v[dropDownValue]);\r\n }}\r\n noneFieldDisplay={noneFieldDisplay}\r\n options={(staticEnum || enumArray || [])\r\n .concat(additional || [])\r\n .concat(\r\n !noEmptyOption\r\n ? [\r\n {\r\n [dropDownValue]: null,\r\n [displayField]:\r\n noneFieldDisplay ||\r\n config.notAllocated.dropdown,\r\n },\r\n ]\r\n : [],\r\n )\r\n .sort((left, right) =>\r\n left && right\r\n ? groupBy\r\n ? groupBy(left)?.localeCompare(groupBy(right))\r\n : onDisplayDropdown\r\n ? onDisplayDropdown(left)?.localeCompare(\r\n onDisplayDropdown(right),\r\n )\r\n : left[displayField]?.localeCompare(\r\n right[displayField],\r\n )\r\n : 0,\r\n )\r\n .filter(\r\n filter ??\r\n function (v) {\r\n return true;\r\n },\r\n )}\r\n helperText={helperText}\r\n errorText={errorText}\r\n getOptionLabel={(v) => {\r\n if (typeof v === 'string') {\r\n if (v.length === 0) {\r\n return (\r\n noneFieldDisplay ?? config.notAllocated.dropdown\r\n );\r\n }\r\n\r\n const result = (staticEnum || enumArray || [])\r\n ?.concat(additional || [])\r\n ?.concat(\r\n !noEmptyOption\r\n ? [\r\n {\r\n [dropDownValue]: null,\r\n [displayField]:\r\n noneFieldDisplay ||\r\n config.notAllocated.dropdown,\r\n },\r\n ]\r\n : [],\r\n )\r\n .find((item) => item[dropDownValue] === v);\r\n if (result && onDisplayDropdown) {\r\n return (\r\n onDisplayDropdown(result) ??\r\n noneFieldDisplay ??\r\n config.notAllocated.dropdown\r\n );\r\n }\r\n return (\r\n result?.[displayField] ??\r\n noneFieldDisplay ??\r\n config.notAllocated.dropdown\r\n );\r\n }\r\n if (onDisplayDropdown) {\r\n return (\r\n onDisplayDropdown(v) ??\r\n noneFieldDisplay ??\r\n config.notAllocated.dropdown\r\n );\r\n }\r\n\r\n return (\r\n v[displayField] ??\r\n noneFieldDisplay ??\r\n config.notAllocated.dropdown\r\n );\r\n }}\r\n displayField={displayField}\r\n dropDownValue={dropDownValue}\r\n label={fieldName}\r\n //groupByProps={groupBy}\r\n onDisplayDropdown={onDisplayDropdown}\r\n renderOption={renderOption}\r\n getOptionSelected={(option, v) => {\r\n return option[dropDownValue] === v;\r\n }}\r\n isRequired={isRequired}\r\n hasTooltip={hasTooltip}\r\n tooltipLabel={tooltipLabel}\r\n {...dropdownProps}\r\n />\r\n );\r\n }\r\n\r\n /*\r\n * If the static enum or the array of possible choices has a length of less than 1\r\n * Render a textfield with a single option\r\n */\r\n if ((staticEnum || enumArray)?.concat(additional || []).length < 1) {\r\n return (\r\n \r\n );\r\n }\r\n\r\n /*\r\n * If there is no staticEnum input into the component then render this\r\n * mainly using props from material ui textfield some some aspects that I do not understand\r\n * This maps the dropDownValue and displayField to a list of MenuItems for the component to use\r\n */\r\n return (\r\n \r\n \r\n {\r\n onChange(e.target.value);\r\n }}\r\n helperText={errorText || helperText}\r\n error={Boolean(errorText)}\r\n variant={'outlined'}\r\n SelectProps={{\r\n IconComponent: CustomChevronDownIcon,\r\n }}\r\n {...dropdownProps}>\r\n {!noEmptyOption && (\r\n \r\n )}\r\n\r\n {dropDownValue && displayField\r\n ? (staticEnum || enumArray)\r\n ?.concat(additional || [])\r\n .map(\r\n (\r\n {\r\n [dropDownValue]: id,\r\n [displayField]: name,\r\n ...rest\r\n },\r\n idx,\r\n ) => {\r\n return (\r\n \r\n );\r\n },\r\n )\r\n : (staticEnum || enumArray)\r\n ?.concat(additional || [])\r\n .map((v, idx) => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default LoadingFieldDropdown;\r\n","import React, { useState, useEffect } from 'react';\r\nimport { useSelector, useDispatch } from 'react-redux';\r\nimport Skeleton from '@material-ui/lab/Skeleton';\r\nimport { MenuItem, FormControl, TextField } from '@material-ui/core';\r\nimport Autocomplete from '@material-ui/lab/Autocomplete';\r\nimport { Box } from '@chakra-ui/react';\r\nimport { ChevronDownIcon } from '@chakra-ui/icons';\r\n\r\nimport ErrorBoundary from '@/components/maintenance/ErrorBoundary';\r\nimport { axios } from '@/services/axios';\r\nimport config from '@/config.json';\r\nimport { customAutoCompleteStyle } from 'pages/navbar/constant';\r\n\r\n// NOTE: copy of LoadingFieldDropdown component, otherwise TCAP will break\r\nconst disabledInputStyle = {\r\n '& input:disabled': {\r\n cursor: 'not-allowed',\r\n },\r\n};\r\n\r\nexport const findCurrentValue = ({\r\n options,\r\n displayField,\r\n dropDownValue,\r\n currentValue,\r\n noneFieldDisplay,\r\n onDisplayDropdown,\r\n}) => {\r\n if (!options || !displayField || !dropDownValue) {\r\n return null;\r\n }\r\n var res = options?.find((v) => {\r\n return v[dropDownValue] === currentValue;\r\n });\r\n\r\n if (!res) {\r\n return noneFieldDisplay || config.notAllocated.dropdown;\r\n }\r\n return (\r\n (onDisplayDropdown && onDisplayDropdown(res)) ||\r\n res[displayField] ||\r\n res ||\r\n 'ERROR:Not Found!!!!'\r\n );\r\n};\r\n\r\n// Specific for 'Company Managing' field on drop down\r\n// Labels company and partner for group by function of autocomplete\r\nexport const relabel = (companies) => {\r\n var res = [];\r\n let parentName = '';\r\n let parentID = '';\r\n for (const company of companies) {\r\n if (company.parent == null || company.parent.length === 0) {\r\n parentName = company.name;\r\n parentID = company.id;\r\n res.push({\r\n id: company.id,\r\n name: company.name,\r\n parentID: '',\r\n parentName: '',\r\n });\r\n } else {\r\n res.push({\r\n id: company.id,\r\n name: company.name,\r\n parentID,\r\n parentName,\r\n });\r\n }\r\n }\r\n return res;\r\n};\r\n\r\nexport const groupBy = (option) => {\r\n if (option.parentName.length === 0) {\r\n return option.name;\r\n }\r\n return option.parentName;\r\n};\r\n\r\nconst getOptionSelectedID = (option, v) => {\r\n return option.id === v.id;\r\n};\r\n\r\nexport const getOptionSelected = (option, value) => {\r\n if (typeof value === 'string') {\r\n return value === option.id;\r\n }\r\n return option.name === value.name;\r\n};\r\n\r\nexport const getOptionLabel = (option) => option.name;\r\n\r\n/*\r\n * SearchBox component used by multi selects, auto completes and drop downs that require search functionality\r\n */\r\nexport function SearchBox(props) {\r\n const [open, setOpen] = useState(false);\r\n const {\r\n placeholder,\r\n defaultValue,\r\n loading,\r\n onChange,\r\n message,\r\n onFocus,\r\n label,\r\n displayField,\r\n dropDownValue,\r\n onDisplayDropdown,\r\n options,\r\n noneFieldDisplay,\r\n helperText,\r\n errorText,\r\n groupByProps,\r\n endAdornment,\r\n renderOption,\r\n getOptionSelected: getOptionSelectedProps,\r\n getOptionLabel: getOptionLabelProps,\r\n dataWalkthroughid,\r\n inputValue,\r\n } = props;\r\n\r\n const { colorScheme } = useSelector((state) => state.settings);\r\n\r\n const findCurrentName = () => {\r\n var res = options.find((v) => {\r\n return v.id === defaultValue;\r\n });\r\n var name = res?.name;\r\n if (res?.parentName) {\r\n name = res?.name + ' Under: ' + res?.parentName;\r\n }\r\n return name;\r\n };\r\n\r\n // For each option you pass in, it must not be null, hence the error boundary\r\n return (\r\n \r\n \r\n {\r\n //ASSUMPTION :ONLY USED WHEN THERE'S GROUP BY?\r\n if (value != null) {\r\n //CHANGE!\r\n const foundItem = options.filter(\r\n (company) =>\r\n company?.[dropDownValue ?? 'id'] ===\r\n value?.[dropDownValue ?? 'id'],\r\n );\r\n onChange(foundItem[0]);\r\n }\r\n }}\r\n onOpen={() => {\r\n setOpen(true);\r\n }}\r\n onClose={() => {\r\n setOpen(false);\r\n }}\r\n groupBy={groupByProps}\r\n getOptionSelected={\r\n getOptionSelectedProps || getOptionSelectedID\r\n }\r\n getOptionLabel={getOptionLabelProps || getOptionLabel}\r\n options={options}\r\n loading={loading}\r\n disableClearable\r\n renderInput={(params) => {\r\n return (\r\n \r\n {loading ? (\r\n \r\n ) : null}\r\n {endAdornment}\r\n {params.InputProps.endAdornment}\r\n \r\n ),\r\n }}\r\n InputLabelProps={{ shrink: true }}\r\n />\r\n );\r\n }}\r\n popupIcon={}\r\n />\r\n \r\n \r\n );\r\n}\r\n\r\n/*\r\n * Component used for drop down fields in the UI that require a series of options\r\n * those options can be gathered from a static list, fetched from the API when the component renders etc\r\n * This component also changes state so that modal forms can submit data using the value from the drop down\r\n */\r\nconst LoadingFieldDropdownWithPlaceholder = ({\r\n // this prop stops the component from fetching until another field/value has data\r\n dependency,\r\n // if there is no field display or we want a different default display then this value is shown\r\n noneFieldDisplay,\r\n // determines when the data will be fetched, if init is true it will be fetched when its loaded\r\n init,\r\n // function that triggers when the display drop down is shown\r\n onDisplayDropdown,\r\n // value behind the noneFieldDisplay as all values have a different display\r\n noneFieldValue,\r\n // prop to determine if its not a modal component\r\n notModalComponent,\r\n // instead of a api fetch the component can be fed a static list to use\r\n staticEnum,\r\n // the onChange function to be passed into the material component of this\r\n onChange,\r\n //\r\n noneField,\r\n // a function that can be passed in to represent a error, usually the onError from TableAndModal.jsx\r\n onError,\r\n // prop to pass through to sub componennts\r\n toggleLimit,\r\n // prop to pass through to sub componennts\r\n loadDependencies,\r\n // boolean to determine whether its searchable or not\r\n searchable,\r\n // the URL for fetching the data to populate the list\r\n fieldFetch,\r\n // label for the component as its a MUI textfield/searchbox\r\n fieldName,\r\n // used to determine the type of the value in the drop down, strint, int, bool etc\r\n fieldValue,\r\n // the value that is used for the state setting when selecting a value\r\n dropDownValue,\r\n // the field that is actually displayed in the drop down\r\n displayField,\r\n // props for the drop down list\r\n dropdownProps,\r\n // makes it so there is no empty option when the field first loads the drop down data\r\n noEmptyOption,\r\n // a function that triggers when the fetch is sucessful\r\n onFieldFetch,\r\n // determins if the component has dependencies\r\n hasDependency,\r\n // additional options for the static array that is passed into this component\r\n additional,\r\n // helper text is set inside the drop down\r\n helperText,\r\n // error text is what is displayed if there is a modalError\r\n errorText,\r\n // a bool that disalbes the drop down\r\n disabled,\r\n // a value to group the results of the api call or static enum by\r\n groupBy,\r\n // funciton that triggers when the funciton is focussed on\r\n onFocus,\r\n // if you want to render whats inside the wrapper as something that isnt a searchbox/textfield\r\n renderOption,\r\n // a filter for the options of the search box\r\n filter,\r\n // icon or any other sort of adornment that goes at the end of the field\r\n endAdornment,\r\n dataWalkthroughid, // used for the walkthrough\r\n placeholder,\r\n inputValue,\r\n getOptionSelected: getOptionSelectedProps,\r\n ...rest\r\n}) => {\r\n const [enumArray, setEnum] = useState(staticEnum || []);\r\n const [enumLoading, setEnumLoading] = useState(false);\r\n\r\n // state to detemine if the modal is showing\r\n const { show: modalShow, state } = useSelector((state) => {\r\n return { ...state.modal };\r\n });\r\n\r\n const dispatch = useDispatch();\r\n\r\n /*\r\n * Fetch function for the results based with onFieldFetch, fieldFetch props\r\n * if this is sucsessful the enum state is set to the result\r\n */\r\n const fetch = () => {\r\n setEnumLoading(true);\r\n if (onFieldFetch) {\r\n onFieldFetch()\r\n .then((res) => {\r\n setEnum(res.data);\r\n setEnumLoading(false);\r\n })\r\n .catch((e) => {\r\n onError(e);\r\n setEnumLoading(false);\r\n });\r\n return;\r\n }\r\n axios\r\n .get(fieldFetch)\r\n .then((res) => {\r\n dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n [fieldName]: res.data,\r\n },\r\n });\r\n setEnum(res.data);\r\n setEnumLoading(false);\r\n })\r\n .catch((e) => {\r\n onError(e);\r\n setEnumLoading(false);\r\n });\r\n };\r\n\r\n /*\r\n * Function to extract the field value\r\n * checks the type of this value and returns the fieldvalue\r\n */\r\n const extractFieldValue = () => {\r\n //set default case\r\n switch (typeof fieldValue) {\r\n case 'object':\r\n return fieldValue || '';\r\n case 'string':\r\n return fieldValue || '';\r\n case 'number':\r\n return fieldValue;\r\n default:\r\n return fieldValue;\r\n }\r\n };\r\n\r\n /*\r\n * calls a fetch based onFieldFetch or fieldFetch existing\r\n * also requires static enum and dependency to be false\r\n * also requires init or modalShow or notModalComponent to execuse fetch()\r\n */\r\n useEffect(() => {\r\n if (\r\n (onFieldFetch || fieldFetch) &&\r\n !staticEnum && //not static\r\n !hasDependency && // not depending on sth else\r\n (init || //do at first place\r\n modalShow ||\r\n notModalComponent)\r\n ) {\r\n fetch();\r\n }\r\n }, [\r\n // onFieldFetch, fieldFetch,\r\n modalShow,\r\n notModalComponent,\r\n staticEnum,\r\n ]);\r\n\r\n /*\r\n * fetches based on the same factors as abovem doesnt accoutn for init or modalShow\r\n * could most likley be refacorted into a single useEffect()\r\n */\r\n useEffect(() => {\r\n if ((onFieldFetch || fieldFetch) && !staticEnum && hasDependency) {\r\n fetch();\r\n }\r\n }, [onFieldFetch, fieldFetch, hasDependency, dependency, staticEnum]);\r\n\r\n /*\r\n * If the enumLoading state is true, returns a skeleton component\r\n */\r\n if (enumLoading) {\r\n return ;\r\n }\r\n\r\n /*\r\n * If the serachable prop is entered with a static enum of length > 0 then render a search box\r\n * many props are used for material ui requirements for SearchBox, documentation is online for those props\r\n */\r\n if (\r\n searchable &&\r\n !disabled &&\r\n (staticEnum || enumArray)?.concat(additional || []).length > 0\r\n ) {\r\n return (\r\n {\r\n onChange(v[dropDownValue]);\r\n }}\r\n noneFieldDisplay={noneFieldDisplay}\r\n options={(staticEnum || enumArray || [])\r\n .concat(additional || [])\r\n .concat(\r\n !noEmptyOption\r\n ? [\r\n {\r\n [dropDownValue]: null,\r\n [displayField]:\r\n noneFieldDisplay || placeholder,\r\n },\r\n ]\r\n : [],\r\n )\r\n .sort((left, right) =>\r\n left && right\r\n ? groupBy\r\n ? groupBy(left)?.localeCompare(groupBy(right))\r\n : onDisplayDropdown\r\n ? onDisplayDropdown(left)?.localeCompare(\r\n onDisplayDropdown(right),\r\n )\r\n : left[displayField]?.localeCompare(\r\n right[displayField],\r\n )\r\n : 0,\r\n )\r\n .filter(\r\n filter ??\r\n function (v) {\r\n return true;\r\n },\r\n )}\r\n helperText={helperText}\r\n errorText={errorText}\r\n getOptionLabel={(v) => {\r\n if (typeof v === 'string') {\r\n if (v.length === 0) {\r\n return noneFieldDisplay ?? placeholder;\r\n }\r\n\r\n const result = (staticEnum || enumArray || [])\r\n ?.concat(additional || [])\r\n ?.concat(\r\n !noEmptyOption\r\n ? [\r\n {\r\n [dropDownValue]: null,\r\n [displayField]:\r\n noneFieldDisplay ||\r\n placeholder,\r\n },\r\n ]\r\n : [],\r\n )\r\n .find((item) => item[dropDownValue] === v);\r\n if (result && onDisplayDropdown) {\r\n return (\r\n onDisplayDropdown(result) ??\r\n noneFieldDisplay ??\r\n placeholder\r\n );\r\n }\r\n return (\r\n result?.[displayField] ??\r\n noneFieldDisplay ??\r\n placeholder\r\n );\r\n }\r\n if (onDisplayDropdown) {\r\n return (\r\n onDisplayDropdown(v) ??\r\n noneFieldDisplay ??\r\n placeholder\r\n );\r\n }\r\n\r\n return v[displayField] ?? noneFieldDisplay ?? placeholder;\r\n }}\r\n displayField={displayField}\r\n dropDownValue={dropDownValue}\r\n label={fieldName}\r\n //groupByProps={groupBy}\r\n onDisplayDropdown={onDisplayDropdown}\r\n renderOption={renderOption}\r\n getOptionSelected={(option, v) => {\r\n return option[dropDownValue] === v;\r\n }}\r\n // {...dropdownProps}\r\n placeholder={placeholder}\r\n />\r\n );\r\n }\r\n\r\n /*\r\n * If the static enum or the array of possible choices has a length of less than 1\r\n * Render a textfield with a single option\r\n */\r\n if ((staticEnum || enumArray)?.concat(additional || []).length < 1) {\r\n return (\r\n \r\n \r\n \r\n );\r\n }\r\n\r\n /*\r\n * If there is no staticEnum input into the component then render this\r\n * mainly using props from material ui textfield some some aspects that I do not understand\r\n * This maps the dropDownValue and displayField to a list of MenuItems for the component to use\r\n */\r\n return (\r\n \r\n \r\n {\r\n onChange(e.target.value);\r\n }}\r\n helperText={errorText || helperText}\r\n error={Boolean(errorText)}\r\n variant={'outlined'}\r\n {...dropdownProps}>\r\n {!noEmptyOption && (\r\n \r\n )}\r\n\r\n {dropDownValue && displayField\r\n ? (staticEnum || enumArray)\r\n ?.concat(additional || [])\r\n .map(\r\n (\r\n {\r\n [dropDownValue]: id,\r\n [displayField]: name,\r\n ...rest\r\n },\r\n idx,\r\n ) => {\r\n return (\r\n \r\n );\r\n },\r\n )\r\n : (staticEnum || enumArray)\r\n ?.concat(additional || [])\r\n .map((v, idx) => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default LoadingFieldDropdownWithPlaceholder;\r\n\r\nLoadingFieldDropdownWithPlaceholder.displayName = 'LoadingFieldDropdown2';\r\n","import { Button } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\n/**\r\n * @typedef {Object} ChakraButtonProps\r\n * @property {import('react').ReactNode} children\r\n * @param {ChakraButtonProps & import('@chakra-ui/react').ButtonProps} props\r\n * @param {import('@chakra-ui/react').ButtonProps} props.rest\r\n * @returns\r\n */\r\nexport default function ChakraButton({ children, ...props }) {\r\n const { colorScheme } = useSelector((state) => state.settings);\r\n const isSecondary =\r\n props.className?.includes('secondary') || props.variant === 'outline';\r\n let bgColor;\r\n\r\n if (props && isSecondary) {\r\n bgColor = 'white';\r\n } else if (colorScheme === 'gray') {\r\n bgColor = 'gray.500';\r\n } else {\r\n bgColor = null;\r\n }\r\n return (\r\n \r\n );\r\n}\r\n","import { Input } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\n/**\r\n * @typedef {Object} ChakraInputProps\r\n * @property {React.RefObject} customRef\r\n * @property {ChakraInputProps & import('@chakra-ui/react').InputProps} props\r\n * @param {ChakraInputProps} customRef\r\n * @param {import('@chakra-ui/react').InputProps} rest\r\n * @returns\r\n */\r\nexport default function ChakraInput({ customRef, ...rest }) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n return (\r\n \r\n );\r\n}\r\n","import {InputGroup} from '@chakra-ui/react';\r\n\r\nexport default function ChakraInputGroup({children, ...rest}) {\r\n return {children};\r\n}\r\n","import { Select } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\n// react multi select uses label instead of name for the option text\r\n// instead of changing every instance of this component to use label instead of name\r\n// ill throw in a quick workaround so I dont need change anything else\r\n/**\r\n * @typedef {Object} ChakraSelectProps\r\n * @property {{label: string, value: string | number}[]} options\r\n * @param {ChakraSelectProps & import('@chakra-ui/react').SelectProps} props\r\n * @returns {JSX.Element}\r\n */\r\nexport default function ChakraSelect({ options, ...props }) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n return (\r\n \r\n );\r\n}\r\n","import {Checkbox} from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\nexport default function ChakraCheckbox({children, ...props}) {\r\n const {darkMode} = useSelector(state => state.settings)\r\n return {children};\r\n}\r\n","import { Heading } from '@chakra-ui/react';\r\n\r\nexport default function ChakraHeading({\r\n children,\r\n fontSize,\r\n fontWeight,\r\n mb,\r\n lineHeight,\r\n fontFamily,\r\n as,\r\n size,\r\n ...rest\r\n}) {\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n}\r\n","export function classNames(...classes) {\r\n return classes.filter(Boolean).join(' ')\r\n}\r\n","import { Text } from '@chakra-ui/react';\r\nimport { useLocation } from 'react-router-dom';\r\nimport { useSelector } from 'react-redux';\r\n\r\nimport { classNames } from '@/utils/classNames';\r\n\r\n/**\r\n * @typedef {Object} ChakraTextProps\r\n * @property {import('react').ReactNode} children\r\n * @param {import('@chakra-ui/react').TextProps & ChakraTextProps} props\r\n * @returns\r\n */\r\nexport default function ChakraText({ children, ...rest }) {\r\n const location = useLocation();\r\n const { pathname } = location;\r\n const textColor = pathname.includes('services') ? 'black' : 'inherit';\r\n const { darkMode } = useSelector((state) => state.settings);\r\n\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n}\r\n","import {Image, forwardRef} from '@chakra-ui/react';\r\n\r\nexport default forwardRef(function ChakraImage(props, ref) {\r\n return ;\r\n});\r\n","import { Box as ChakraBox, forwardRef } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\nconst BoxWithBorder = forwardRef((props, ref) => {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n return (\r\n \r\n );\r\n});\r\n\r\nexport { BoxWithBorder };\r\n","import { FormLabel, forwardRef } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\n/**\r\n * @typedef {import('@chakra-ui/react').FormLabelProps} LabelProps\r\n * @type React.ForwardRefRenderFunction\r\n * @returns {JSX.Element}\r\n */\r\nexport default forwardRef(function ChakraInput(props, ref) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n const textColor = darkMode ? 'white' : 'black';\r\n return (\r\n \r\n {props.children}\r\n \r\n );\r\n});\r\n","import { FormControl } from '@chakra-ui/react';\r\n\r\n/**\r\n * @typedef {Object} ChakraFormControlProps\r\n * @property {import('react').ReactNode} children\r\n * @param {ChakraFormControlProps & import('@chakra-ui/react').FormControlProps} props\r\n * @param {import('@chakra-ui/react').FormControlProps} props.rest\r\n * @returns\r\n */\r\nexport default function ChakraFormControl({ children, ...rest }) {\r\n return {children};\r\n}\r\n","import { Alert } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\nconst STATUSES = {\r\n info: { colorScheme: 'blue' },\r\n warning: { colorScheme: 'orange' },\r\n success: { colorScheme: 'green' },\r\n error: { colorScheme: 'red' },\r\n};\r\n\r\nconst variant = (status) => ({\r\n 'inline-accent': {\r\n borderRadius: 'md',\r\n borderInlineWidth: '3px',\r\n borderColor: `var(--chakra-colors-${STATUSES[status].colorScheme}-500)`,\r\n py: 2,\r\n minH: '40px',\r\n },\r\n});\r\n/**\r\n * @typedef {Object} ChakraAlertProps\r\n * @property {import('@chakra-ui/react').AlertProps} props\r\n * @property {import('react').ReactNode} props.children\r\n * @property {'left-accent' | 'inline-accent' | 'solid' | 'subtle'} props.variant\r\n */\r\n\r\n/**\r\n * @param {import('@chakra-ui/react').AlertProps & ChakraAlertProps} props\r\n */\r\nexport default function ChakraAlert({ children, ...props }) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n const setAlertStatusBg = (status) => {\r\n switch (status) {\r\n case 'error': {\r\n return darkMode ? 'rgba(254, 178, 178, 0.16)' : null;\r\n }\r\n\r\n case 'info': {\r\n return darkMode ? 'rgba(144, 205, 244, 0.16)' : null;\r\n }\r\n\r\n case 'success': {\r\n return darkMode ? 'rgba(154, 230, 180, 0.16)' : null;\r\n }\r\n\r\n case 'warning': {\r\n return darkMode ? 'rgba(251, 211, 141, 0.16)' : null;\r\n }\r\n\r\n default: {\r\n return null;\r\n }\r\n }\r\n };\r\n const alertBg = setAlertStatusBg(props.status);\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n}\r\n","import {AlertDescription} from '@chakra-ui/react';\r\n\r\nexport default function ChakraAlertDescription({children, ...rest}) {\r\n return {children};\r\n}\r\n","import {AlertIcon} from '@chakra-ui/react';\r\n\r\nexport default function ChakraAlertIcon({...rest}) {\r\n return ;\r\n}\r\n","import { Modal } from '@chakra-ui/react';\r\n\r\nexport default function ChakraModal({\r\n children,\r\n closeOnOverlayClick = false,\r\n autoFocus = false,\r\n ...props\r\n}) {\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n}\r\n","import { ModalOverlay } from '@chakra-ui/react';\r\n\r\nexport default function ChakraModalOverlay({ ...props }) {\r\n return ;\r\n}\r\n","import {ModalContent} from '@chakra-ui/react';\r\nimport {useSelector} from 'react-redux';\r\n\r\nexport default function ChakraModalContent({children, ...props}) {\r\n const {darkMode} = useSelector((state) => state.settings)\r\n const modalBg = darkMode ? 'dark.tcap' : 'white'\r\n return {children};\r\n}\r\n","import {ModalHeader} from '@chakra-ui/react';\r\nimport {useSelector} from 'react-redux';\r\n\r\nexport default function ChakraModalHeader({children, ...props}) {\r\n const {darkMode} =useSelector((state) => state.settings);\r\n return {children};\r\n}\r\n","import {ModalBody} from '@chakra-ui/react';\r\n\r\nexport default function ChakraModalBody({children, ...props}) {\r\n return {children};\r\n}\r\n","import { ModalFooter } from '@chakra-ui/react';\r\n\r\nexport default function ChakraModalFooter({ children, ...props }) {\r\n return {children};\r\n}\r\n","import {CircularProgress} from '@chakra-ui/react';\r\n\r\nexport default function LoadingIndicator(props) {\r\n return (\r\n \r\n );\r\n}\r\n","import { MenuItem } from '@chakra-ui/react';\r\nimport { useSelector } from 'react-redux';\r\n\r\n/**\r\n * @typedef {Object} ChakraMenuItemProps\r\n * @property {import('react').ReactNode} children\r\n * @param {import('@chakra-ui/react').MenuItemProps} props\r\n */\r\nexport default function ChakraMenuItem({ children, ...props }) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n return (\r\n \r\n );\r\n}\r\n","import { useSelector } from 'react-redux';\r\nimport { MenuList } from '@chakra-ui/react';\r\n\r\n/**\r\n * @typedef {Object} ChakraMenuItemProps\r\n * @property {import('react').ReactNode} children\r\n * @param {import('@chakra-ui/react').MenuListProps} props\r\n */\r\nconst ChakraMenuList = ({ children, ...props }) => {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n\r\n const bgColorCondition = {\r\n bg: darkMode ? 'rgba(255, 255, 255, 0.16)' : 'gray.200',\r\n };\r\n\r\n const menuListStyle = {\r\n '& a': bgColorCondition,\r\n button: {\r\n '&:hover': bgColorCondition,\r\n },\r\n 'button[role=\"menuitem\"]:active': bgColorCondition,\r\n };\r\n\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n};\r\n\r\nexport default ChakraMenuList;\r\n","import { motion } from 'framer-motion';\r\nimport { useLayoutContext } from 'context/LayoutContext';\r\n\r\nexport const AnimatedTextWord = ({ text }) => {\r\n const words = text.split(' ');\r\n const { isMenuCollapse } = useLayoutContext();\r\n\r\n const container = {\r\n hidden: { opacity: 0 },\r\n\r\n visible: (i = 1) => ({\r\n opacity: 1,\r\n transition: {\r\n staggerChildren: 0.36,\r\n delayChildren: 0.04 * i,\r\n },\r\n }),\r\n };\r\n\r\n const child = {\r\n visible: {\r\n opacity: 1,\r\n x: 0,\r\n transition: {\r\n type: 'spring',\r\n damping: 12,\r\n stiffness: 100,\r\n },\r\n },\r\n hidden: {\r\n opacity: 0,\r\n x: -20,\r\n transition: {\r\n type: 'spring',\r\n damping: 12,\r\n stiffness: 100,\r\n },\r\n },\r\n };\r\n\r\n return (\r\n \r\n {words.map((word, i) => (\r\n \r\n {word}\r\n \r\n ))}\r\n \r\n );\r\n};\r\n","export const _focus = '_focus';\r\nexport const _active = '_active';\r\nexport const _hover = '_hover';\r\n\r\nexport const colorMode = {\r\n [_focus]: {\r\n bg: 'whiteAlpha.300',\r\n },\r\n [_active]: {\r\n bg: 'whiteAlpha.300',\r\n },\r\n [_hover]: {\r\n bg: 'whiteAlpha.100',\r\n },\r\n};\r\nexport const accordionItemStyle = {\r\n '.chakra-stack .chakra-text': {\r\n marginInlineStart: 0,\r\n },\r\n\r\n '&': {\r\n marginBottom: 1,\r\n },\r\n '& .chakra-stack :where(.chakra-button)': {\r\n margin: 0,\r\n },\r\n};\r\n","import { useSelector } from 'react-redux';\r\nimport { deepmerge } from '@mui/utils';\r\nimport { createTheme } from '@mui/material/styles';\r\n\r\nimport chakratheme from '@/chakratheme';\r\n\r\n/**\r\n * @description Custom hook to merge chakra theme with mui theme\r\n * @returns {import('@mui/material/styles').Theme} theme\r\n */\r\nexport function useDeepMerge() {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n const theme = createTheme(\r\n deepmerge(chakratheme, {\r\n palette: { mode: darkMode ? 'dark' : 'light' },\r\n shadows: Array(25).fill('none'),\r\n }),\r\n );\r\n\r\n return { theme, chakratheme };\r\n}\r\n","import { axios } from '@/services/axios';\r\n\r\nexport const getResourceAccounts = async (currentCompany) => {\r\n const res = await axios.get(`/ResourceAccounts/${currentCompany}`);\r\n return res.data;\r\n};\r\n","import classNames from 'classnames';\r\nimport {Box} from '@chakra-ui/react';\r\n\r\nexport default function Grid({\r\n // Grid\r\n rows,\r\n columns,\r\n gap,\r\n gapX,\r\n gapY,\r\n // Used to pass in gaps (for now)\r\n className,\r\n // Other\r\n children,\r\n ...rest\r\n}) {\r\n const _columns = {\r\n 1: 'grid-cols-1',\r\n 2: 'grid-cols-2',\r\n 3: 'grid-cols-3',\r\n 4: 'grid-cols-4',\r\n 5: 'grid-cols-5',\r\n 6: 'grid-cols-6',\r\n 7: 'grid-cols-7',\r\n 8: 'grid-cols-8',\r\n 9: 'grid-cols-9',\r\n 10: 'grid-cols-10',\r\n 11: 'grid-cols-11',\r\n 12: 'grid-cols-12',\r\n }[columns];\r\n\r\n const _rows = {\r\n 1: 'grid-rows-1',\r\n 2: 'grid-rows-2',\r\n 3: 'grid-rows-3',\r\n 4: 'grid-rows-4',\r\n 5: 'grid-rows-5',\r\n 6: 'grid-rows-6',\r\n 7: 'grid-rows-7',\r\n 8: 'grid-rows-8',\r\n 9: 'grid-rows-9',\r\n 10: 'grid-rows-10',\r\n 11: 'grid-rows-11',\r\n 12: 'grid-rows-12',\r\n }[rows];\r\n\r\n const _gap = {\r\n 0: 'gap-0',\r\n 1: 'gap-1',\r\n 2: 'gap-2',\r\n 3: 'gap-3',\r\n 4: 'gap-4',\r\n 5: 'gap-5',\r\n 6: 'gap-6',\r\n 7: 'gap-7',\r\n 8: 'gap-8',\r\n 9: 'gap-9',\r\n 10: 'gap-10',\r\n }[gap];\r\n\r\n const _gapX = {\r\n 0: 'gap-x-0',\r\n 1: 'gap-x-1',\r\n 2: 'gap-x-2',\r\n 3: 'gap-x-3',\r\n 4: 'gap-x-4',\r\n 5: 'gap-x-5',\r\n 6: 'gap-x-6',\r\n 7: 'gap-x-7',\r\n 8: 'gap-x-8',\r\n 9: 'gap-x-9',\r\n 10: 'gap-x-10',\r\n }[gapX];\r\n\r\n const _gapY = {\r\n 0: 'gap-y-0',\r\n 1: 'gap-y-1',\r\n 2: 'gap-y-2',\r\n 3: 'gap-y-3',\r\n 4: 'gap-y-4',\r\n 5: 'gap-y-5',\r\n 6: 'gap-y-6',\r\n 7: 'gap-y-7',\r\n 8: 'gap-y-8',\r\n 9: 'gap-y-9',\r\n 10: 'gap-y-10',\r\n }[gapY];\r\n\r\n const gridClasses = classNames(\r\n 'grid',\r\n className,\r\n _columns,\r\n _rows,\r\n _gap,\r\n _gapX,\r\n _gapY,\r\n );\r\n\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n}\r\n","export default {\r\n modal: {\r\n ufModalProgress: 'modal/input/progress',\r\n ufModalCancelBtn: 'modal/button/cancel',\r\n },\r\n table: {\r\n ufAddActionBtn: 'table/button/addAction',\r\n ufDeleteActionBtn: 'table/button/deleteAction',\r\n ufEditActionBtn: 'table/button/editAction',\r\n }\r\n}","import React, { forwardRef } from 'react';\r\n\r\nimport AddBox from '@mui/icons-material/AddBox';\r\nimport ArrowDownward from '@mui/icons-material/ArrowDownward';\r\nimport Check from '@mui/icons-material/Check';\r\nimport ChevronLeft from '@mui/icons-material/ChevronLeft';\r\nimport ChevronRight from '@mui/icons-material/ChevronRight';\r\nimport ExpandLess from '@mui/icons-material/ExpandLess';\r\nimport ExpandMore from '@mui/icons-material/ExpandMore';\r\nimport Clear from '@mui/icons-material/Clear';\r\nimport DeleteOutline from '@mui/icons-material/DeleteOutline';\r\nimport Edit from '@mui/icons-material/Edit';\r\nimport FilterList from '@mui/icons-material/FilterList';\r\nimport FirstPage from '@mui/icons-material/FirstPage';\r\nimport LastPage from '@mui/icons-material/LastPage';\r\nimport Remove from '@mui/icons-material/Remove';\r\nimport SaveAlt from '@mui/icons-material/SaveAlt';\r\nimport Search from '@mui/icons-material/Search';\r\nimport ViewColumn from '@mui/icons-material/ViewColumn';\r\nimport Refresh from '@mui/icons-material/Refresh';\r\n\r\nimport walkthroughIds from './walkthroughIds';\r\n\r\nconst tableIcons = {\r\n Add: forwardRef((props, ref) => (\r\n \r\n )),\r\n Check: forwardRef((props, ref) => ),\r\n Clear: forwardRef((props, ref) => ),\r\n Delete: forwardRef((props, ref) => (\r\n \r\n )),\r\n DetailPanel: forwardRef((props, ref) => (\r\n \r\n )),\r\n MoveUp: forwardRef((props, ref) => ),\r\n MoveDown: forwardRef((props, ref) => ),\r\n Edit: forwardRef((props, ref) => (\r\n \r\n )),\r\n Export: forwardRef((props, ref) => ),\r\n Filter: forwardRef((props, ref) => ),\r\n FirstPage: forwardRef((props, ref) => ),\r\n LastPage: forwardRef((props, ref) => ),\r\n NextPage: forwardRef((props, ref) => ),\r\n PreviousPage: forwardRef((props, ref) => (\r\n \r\n )),\r\n ResetSearch: forwardRef((props, ref) => ),\r\n Search: forwardRef((props, ref) => ),\r\n SortArrow: forwardRef((props, ref) => (\r\n \r\n )),\r\n ThirdStateCheck: forwardRef((props, ref) => (\r\n \r\n )),\r\n ViewColumn: forwardRef((props, ref) => ),\r\n Refresh: forwardRef((props, ref) => ),\r\n};\r\n\r\nexport default tableIcons;\r\n","import { useSelector } from 'react-redux';\r\nimport {\r\n Box as ChakraBox,\r\n Button as ChakraButton,\r\n ChakraProvider,\r\n FormControl,\r\n ModalOverlay,\r\n Stack,\r\n Tooltip,\r\n} from '@chakra-ui/react';\r\nimport { Select } from 'chakra-react-select';\r\n\r\nimport {\r\n Modal,\r\n ModalContent,\r\n ModalBody,\r\n ModalHeader,\r\n ModalFooter,\r\n Input,\r\n FormLabel,\r\n Checkbox as ChakraCheckbox,\r\n} from '@/components/v4';\r\n\r\nimport chakratheme, {\r\n floatingLabelStyles as floatingStyle,\r\n} from '@/chakratheme';\r\n\r\nimport { chakraSelectDarkMode, defaultChakraSelectStyle } from '@/constants';\r\nexport default function BillingNotesModal({\r\n isOpen,\r\n onClose,\r\n modal,\r\n desc,\r\n setDesc,\r\n scopes,\r\n setScope,\r\n locations,\r\n location,\r\n setLocation,\r\n isActive,\r\n setIsActive,\r\n onSubmitHandler,\r\n}) {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n const chakraSelectDark = chakraSelectDarkMode(darkMode);\r\n const floatingLabelStyles = floatingStyle(darkMode);\r\n\r\n const chakraStyles = {\r\n ...defaultChakraSelectStyle,\r\n ...chakraSelectDark,\r\n };\r\n return (\r\n \r\n \r\n \r\n\r\n \r\n Billing Note\r\n \r\n Please enter a billing note description\r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n","export const invoiceFormatList = [\r\n {\r\n title: 'CDR',\r\n contents: [\r\n {\r\n fields: {\r\n label: 'CDR Detail Fields',\r\n value: 'cdrDetailFields',\r\n },\r\n format: {\r\n label: 'CDR Detail Format',\r\n value: 'cdrDetailFormat',\r\n defaultValue: 'cdrDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'CDR Summary Fields',\r\n value: 'cdrSummaryFields',\r\n },\r\n format: {\r\n label: 'CDR Summary Format',\r\n value: 'cdrSummaryFormat',\r\n defaultValue: 'cdrSummaryDefaultFormat',\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n title: 'Number Block',\r\n contents: [\r\n {\r\n fields: {\r\n label: 'Number Block Detail Fields',\r\n value: 'numberBlockDetailFields',\r\n },\r\n format: {\r\n label: 'Number Block Detail Format',\r\n value: 'numberBlockDetailFormat',\r\n defaultValue: 'numberBlockDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'Number Block Porting Detail Fields',\r\n value: 'numberBlockPortingDetailFields',\r\n },\r\n format: {\r\n label: 'Number Block Porting Detail Format',\r\n value: 'numberBlockPortingDetailFormat',\r\n defaultValue: 'numberBlockPortingDetailDefaultFormat',\r\n },\r\n },\r\n {\r\n fields: {\r\n label: 'Number Block Setup Detail Fields',\r\n value: 'numberBlockSetupDetailFields',\r\n },\r\n format: {\r\n label: 'Number Block Setup Detail Format',\r\n value: 'numberBlockSetupDetailFormat',\r\n defaultValue: 'numberBlockSetupDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'Number Block Summary Fields',\r\n value: 'numberBlockSummaryFields',\r\n },\r\n format: {\r\n label: 'Number Block Summary Format',\r\n value: 'numberBlockSummaryFormat',\r\n defaultValue: 'numberBlockSummaryDefaultFormat',\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n title: 'RGS',\r\n contents: [\r\n {\r\n fields: {\r\n label: 'RGS Detail Fields',\r\n value: 'rgsDetailFields',\r\n },\r\n format: {\r\n label: 'RGS Detail Format',\r\n value: 'rgsDetailFormat',\r\n defaultValue: 'rgsDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'RGS Setup Detail Fields',\r\n value: 'rgsSetupDetailFields',\r\n },\r\n format: {\r\n label: 'RGS Setup Detail Format',\r\n value: 'rgsSetupDetailFormat',\r\n defaultValue: 'rgsSetupDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'RGS Summary Fields',\r\n value: 'rgsSummaryFields',\r\n },\r\n format: {\r\n label: 'RGS Summary Format',\r\n value: 'rgsSummaryFormat',\r\n defaultValue: 'rgsSummaryDefaultFormat',\r\n },\r\n },\r\n ],\r\n },\r\n\r\n {\r\n title: 'User',\r\n contents: [\r\n {\r\n fields: {\r\n label: 'User Detail Fields',\r\n value: 'userDetailFields',\r\n },\r\n format: {\r\n label: 'User Detail Format',\r\n value: 'userDetailFormat',\r\n defaultValue: 'userDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'User Setup Detail Fields',\r\n value: 'userSetupDetailFields',\r\n },\r\n format: {\r\n label: 'User Setup Detail Format',\r\n value: 'userSetupDetailFormat',\r\n defaultValue: 'userSetupDetailDefaultFormat',\r\n },\r\n },\r\n\r\n {\r\n fields: {\r\n label: 'User Summary Fields',\r\n value: 'userSummaryFields',\r\n },\r\n format: {\r\n label: 'User Summary Format',\r\n value: 'userSummaryFormat',\r\n defaultValue: 'userSummaryDefaultFormat',\r\n },\r\n },\r\n ],\r\n },\r\n];\r\n\r\nexport const customTablePaperStyle = (darkMode) => ({\r\n boxShadow: darkMode\r\n ? 'none'\r\n : '0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)',\r\n '&& .Mui-selected, &.Mui-focusVisible': {\r\n backgroundColor: darkMode\r\n ? 'rgba(255, 255, 255, 0.26)'\r\n : 'var(--chakra-colors-gray-100)',\r\n '&:hover': {\r\n backgroundColor: darkMode\r\n ? 'var(--chakra-colors-whiteAlpha-300)'\r\n : 'var(--chakra-colors-gray-200)',\r\n },\r\n },\r\n '& .MuiMenu-list': {\r\n li: {\r\n display: 'flex',\r\n padding: '6px 16px',\r\n '&:hover': {\r\n backgroundColor: darkMode\r\n ? 'var(--chakra-colors-whiteAlpha-300)'\r\n : 'var(--chakra-colors-gray-200)',\r\n },\r\n },\r\n },\r\n});\r\n","import {\r\n Box,\r\n MenuItem,\r\n Checkbox as MuiCheckbox,\r\n TextField as MuiTextField,\r\n Tooltip,\r\n} from '@mui/material';\r\n\r\nimport MaterialTable from 'material-table';\r\nimport { forwardRef, useEffect, useMemo, useState } from 'react';\r\nimport { useDispatch, useSelector } from 'react-redux';\r\nimport Edit from '@mui/icons-material/Edit';\r\nimport { useDisclosure } from '@chakra-ui/react';\r\n\r\nimport { createTheme, ThemeProvider } from '@material-ui/core/styles';\r\nimport tableIcons from '../../../utils/MaterialTableIcons';\r\nimport BillingNotesModal from './BillingNotesModal';\r\n\r\nimport store from '@/store/store';\r\nimport walkthroughIds from '../walkthroughIds';\r\nimport { customTablePaperStyle } from './constants';\r\n\r\nconst Checkbox = forwardRef((props, ref) => {\r\n return (\r\n \r\n );\r\n});\r\n\r\nCheckbox.displayName = 'Checkbox';\r\n\r\nconst TextField = forwardRef((props, ref) => {\r\n const { darkMode } = useSelector((state) => state.settings);\r\n return (\r\n \r\n );\r\n});\r\n\r\nTextField.displayName = 'TextField';\r\n\r\n// default columns for the table\r\nconst columns = [\r\n {\r\n field: 'description',\r\n title: ' Billing Note',\r\n width: 570,\r\n editComponent: (props) => {\r\n return (\r\n {\r\n props.onChange(e.target.value);\r\n }}\r\n />\r\n );\r\n },\r\n },\r\n {\r\n field: 'requiredScope',\r\n title: 'Scope',\r\n width: 125,\r\n editComponent: (props) => {\r\n return (\r\n props.onChange(e.target.value)}>\r\n {scopes.map((option) => (\r\n \r\n ))}\r\n \r\n );\r\n },\r\n },\r\n {\r\n field: 'isActive',\r\n title: 'Active',\r\n width: 120,\r\n type: 'boolean',\r\n render: (rowData) => {\r\n return (\r\n \r\n {\r\n store.dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n rowClicked: rowData?.tableData?.id,\r\n },\r\n });\r\n }}\r\n onMouseLeave={() => {\r\n store.dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n rowClicked: -1,\r\n },\r\n });\r\n }}\r\n checked={rowData.isActive}\r\n className=\"hover:cursor-not-allowed\"\r\n readOnly\r\n />\r\n \r\n );\r\n },\r\n editComponent: (props) => {\r\n return (\r\n props.onChange(e.target.checked)}\r\n />\r\n );\r\n },\r\n },\r\n {\r\n field: 'billingNoteLocation',\r\n title: 'Display Location',\r\n width: 220,\r\n render: (rowData) => {\r\n if (rowData.billingNoteLocation === 0) {\r\n return 'Top';\r\n }\r\n if (rowData.billingNoteLocation === 1) {\r\n return 'Bottom';\r\n } else {\r\n return 'Top';\r\n }\r\n },\r\n editComponent: (props) => {\r\n return (\r\n props.onChange(e.target.value)}>\r\n {locations.map((option) => (\r\n \r\n ))}\r\n \r\n );\r\n },\r\n },\r\n];\r\n// enums for inputs\r\nconst scopes = [\r\n { value: 20, label: 20 },\r\n { value: 40, label: 40 },\r\n { value: 60, label: 60 },\r\n { value: 80, label: 80 },\r\n];\r\nconst locations = [\r\n { value: 0, label: 'Top' },\r\n { value: 1, label: 'Bottom' },\r\n];\r\n\r\n/**\r\n * Table that is displayed in the billing note section of the company billing form\r\n */\r\nconst BillingNoteTable = (props) => {\r\n const muiTheme = useMemo(\r\n () =>\r\n createTheme({\r\n typography: {\r\n color: '#000000',\r\n },\r\n head: {\r\n backgroundColor: null,\r\n },\r\n overrides: {\r\n MuiToolbar: {\r\n root: {\r\n color: 'rgba(255,255,255, 0.7)',\r\n backgroundColor: '#424242',\r\n },\r\n },\r\n MuiTable: {\r\n root: {\r\n WebkitTextFillColor:\r\n 'rgba(255, 255, 255, 0.7) !important',\r\n backgroundColor: '#424242 !important',\r\n },\r\n },\r\n MuiTableHead: {\r\n root: {\r\n backgroundColor: '#424242 !important',\r\n },\r\n },\r\n MuiTableCell: {\r\n root: {\r\n borderBottom: null,\r\n borderTop: '1px solid rgba(224, 224, 224, 0.1)',\r\n },\r\n },\r\n MuiTablePagination: {\r\n root: {\r\n backgroundColor: 'white',\r\n },\r\n },\r\n MuiPaper: {\r\n root: {\r\n backgroundColor: null,\r\n },\r\n },\r\n MuiIconButton: {\r\n label: {\r\n color: 'rgba(255, 255, 255, 0.3)',\r\n },\r\n },\r\n },\r\n }),\r\n [],\r\n );\r\n\r\n const dispatch = useDispatch();\r\n const { setBillingState } = props;\r\n const [isActive, setIsActive] = useState(true);\r\n const [desc, setDesc] = useState();\r\n const [location, setLocation] = useState(0);\r\n const [scope, setScope] = useState(20);\r\n const [rows, setRows] = useState([]);\r\n const [loading] = useState(false);\r\n\r\n // state access\r\n const { state } = useSelector((state) => {\r\n return {\r\n ...state.modal,\r\n };\r\n });\r\n const { rowClicked } = state || -1;\r\n\r\n const { darkMode } = useSelector((state) => state.settings);\r\n\r\n const { isOpen, onOpen, onClose } = useDisclosure();\r\n\r\n const { modal } = walkthroughIds.companies.billing;\r\n\r\n // function for when the modal is submitted, ie a note is added\r\n const onSubmitHandler = () => {\r\n let tempNotes;\r\n if (state.companyBillingSettings) {\r\n tempNotes = [\r\n ...state.companyBillingSettings.billingNotes,\r\n {\r\n requiredScope: scope,\r\n billingNoteLocation: location,\r\n description: desc,\r\n isActive: isActive,\r\n billingSettingsID: state.companyBillingSettings.id,\r\n },\r\n ];\r\n } else {\r\n tempNotes = [\r\n {\r\n requiredScope: scope,\r\n billingNoteLocation: location,\r\n description: desc,\r\n isActive: isActive,\r\n billingSettingsID: state.companyBillingSettings.id,\r\n },\r\n ];\r\n }\r\n setBillingState({ billingNotes: tempNotes });\r\n onClose();\r\n };\r\n\r\n // append rows based on the state\r\n useEffect(() => {\r\n if (state?.companyBillingSettings?.billingNotes && loading === false) {\r\n let result = [];\r\n state.companyBillingSettings.billingNotes.forEach((v) => {\r\n const temp = {\r\n ...v,\r\n };\r\n result.push(temp);\r\n });\r\n setRows([...result]);\r\n }\r\n }, [state?.companyBillingSettings?.billingNotes, loading]);\r\n\r\n // sets array so dispatch can spread empty array for delete handling\r\n useEffect(() => {\r\n if (state.deletedNoteIDs === undefined) {\r\n dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n deletedNoteIDs: [],\r\n },\r\n });\r\n }\r\n }, []);\r\n\r\n const billingNotesModalProps = {\r\n isOpen,\r\n onClose,\r\n modal,\r\n desc,\r\n setDesc,\r\n scopes,\r\n setScope,\r\n locations,\r\n location,\r\n setLocation,\r\n isActive,\r\n setIsActive,\r\n onSubmitHandler,\r\n };\r\n\r\n const foundRowClicked = rows.find(\r\n (row) => row?.tableData?.id === rowClicked,\r\n );\r\n\r\n // table that billing notes renders\r\n return (\r\n \r\n \r\n (\r\n \r\n ),\r\n }}\r\n columns={columns}\r\n data={rows}\r\n options={{\r\n actionsColumnIndex: -1,\r\n search: false,\r\n sorting: true,\r\n pageSize: 3,\r\n pageSizeOptions: [],\r\n draggable: false,\r\n }}\r\n actions={[\r\n {\r\n icon: tableIcons.Add,\r\n tooltip: 'Add',\r\n isFreeAction: true,\r\n onClick: onOpen,\r\n },\r\n ]}\r\n editable={{\r\n onRowDelete: (oldData) =>\r\n new Promise((resolve) => {\r\n setTimeout(() => {\r\n const dataDelete = [...rows];\r\n const index = oldData.tableData.id;\r\n dataDelete.splice(index, 1);\r\n setRows([...dataDelete]);\r\n dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n deletedNoteIDs: [\r\n {\r\n id: oldData.id,\r\n },\r\n ...state.deletedNoteIDs,\r\n ],\r\n },\r\n });\r\n dispatch({\r\n type: 'CHANGE_MODAL_STATE',\r\n payload: {\r\n companyBillingSettings: {\r\n ...state.companyBillingSettings,\r\n billingNotes: dataDelete,\r\n },\r\n },\r\n });\r\n resolve();\r\n }, 1000);\r\n }),\r\n onRowUpdate: (newData, oldData) =>\r\n new Promise((resolve) => {\r\n setTimeout(() => {\r\n const dataUpdate = [...rows];\r\n const index = oldData.tableData.id;\r\n dataUpdate[index] = newData;\r\n setRows([...dataUpdate]);\r\n let result = [];\r\n state.companyBillingSettings.billingNotes.forEach(\r\n (v) => {\r\n if (\r\n v.description ===\r\n oldData.description\r\n ) {\r\n // if one state value matches the old data - update this value\r\n const temp = {\r\n ...newData,\r\n id: v.id,\r\n };\r\n result.push(temp);\r\n } else {\r\n // make sure to grab that host and keep it in state\r\n const temp = { ...v };\r\n result.push(temp);\r\n }\r\n },\r\n );\r\n setBillingState({\r\n billingNotes: result,\r\n });\r\n resolve();\r\n }, 1000);\r\n }),\r\n }}\r\n localization={{\r\n header: {\r\n actions: '',\r\n },\r\n body: {\r\n editRow: {\r\n deleteText:\r\n 'Are you sure you want to delete this note?',\r\n },\r\n },\r\n }}\r\n />\r\n \r\n\r\n {/* Diaglogue that opens when you add a billing note */}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default BillingNoteTable;\r\n","import NumberFormat from 'react-number-format';\r\n\r\n/*\r\n * A series of number format methods\r\n */\r\nconst NumberFormatCustom = (props) => {\r\n const { inputRef, onChange, allowNegative = false, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={allowNegative}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={6}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\n/*\r\n * A series of number format methods\r\n */\r\nexport const NegativeSixDP = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={6}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport const Dollar = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={false}\r\n thousandSeparator\r\n isNumericString\r\n prefix=\"$\"\r\n decimalScale={2}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport const FloatAllowNegative = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={true}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={6}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport const FloatSurchargePercentage = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={true}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={6}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport const FloatSurcharge = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={true}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={6}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\nexport const NonNegativeInteger = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={false}\r\n thousandSeparator\r\n isNumericString\r\n decimalScale={0}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport const PhoneNumber = (props) => {\r\n const { inputRef, onChange, ...other } = props;\r\n\r\n return (\r\n {\r\n onChange &&\r\n onChange({\r\n target: {\r\n name: props.name,\r\n value: values.value,\r\n },\r\n });\r\n }}\r\n allowNegative={false}\r\n isNumericString\r\n decimalScale={0}\r\n fixedDecimalScale={true}\r\n />\r\n );\r\n};\r\n\r\nexport default NumberFormatCustom;\r\n","import React from 'react';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport Button from '@material-ui/core/Button';\r\nimport { Modal } from 'react-bootstrap';\r\nimport { classNames } from 'utils/classNames';\r\nimport { useSelector } from 'react-redux';\r\n\r\n// theme usage with material ui\r\nconst useStyles = makeStyles((theme) => ({\r\n root: {\r\n maxWidth: '100%',\r\n flexGrow: 1,\r\n },\r\n header: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n height: 50,\r\n paddingLeft: theme.spacing(4),\r\n backgroundColor: theme.palette.background.default,\r\n },\r\n img: {\r\n overflow: 'hidden',\r\n display: 'block',\r\n width: '100%',\r\n },\r\n content: {\r\n padding: '5%',\r\n },\r\n}));\r\n\r\n// Restore to default confirmation modal\r\nconst RestoreDefaultModal = ({ handleClose, show, handleSubmit, content }) => {\r\n const classes = useStyles();\r\n\r\n const { darkMode } = useSelector((state) => state.settings);\r\n\r\n return (\r\n \r\n \r\n Restore To Default \r\n \r\n \r\n