(false)\r\n const { width } = useWindowSize()\r\n\r\n useLayoutEffect(() => {\r\n if (width >= Number(extraLargeScreen.replace(/\\D*/g, ''))) {\r\n setShowMenuSidebar(false)\r\n }\r\n }, [width])\r\n\r\n useLockedBody(showMenuSidebar)\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}\r\n","import { DEFAULT_ERROR_MESSAGE } from 'common/constants'\r\nimport { PropsWithChildren } from 'react'\r\nimport { Alert } from 'react-bootstrap'\r\nimport { ErrorBoundary, withErrorBoundary } from 'react-error-boundary'\r\n\r\nconst ErrorFallback = () => {\r\n return {DEFAULT_ERROR_MESSAGE}\r\n}\r\n\r\nexport const DefaultErrorBoundary = ({ children }: PropsWithChildren<{}>) => (\r\n {children}\r\n)\r\n\r\nexport function withDefaultErrorBoundary(component: React.ComponentType
) {\r\n return withErrorBoundary
(component, {\r\n FallbackComponent: ErrorFallback\r\n })\r\n}\r\n","export const roundUpToNearest = (newValue: number, oldValue: number, roundUpTo) => {\r\n const diff = roundUpTo - ((newValue - oldValue) % roundUpTo)\r\n return diff === roundUpTo ? newValue : newValue + diff\r\n}\r\n\r\nexport const formatNumber = (value: number, options?: Intl.NumberFormatOptions) => {\r\n if (!value && value !== 0) {\r\n return ''\r\n }\r\n\r\n const formatOptions = {\r\n minimumFractionDigits: 0,\r\n ...options\r\n }\r\n\r\n const format = new Intl.NumberFormat('en-US', formatOptions)\r\n\r\n return format.format(value)\r\n}\r\n","import { useMemo, useReducer } from 'react'\r\n\r\ninterface IExpandAction {\r\n type: string\r\n value?: boolean\r\n index?: number\r\n totalGroup?: number\r\n defaultGroupOpen?: boolean[]\r\n}\r\n\r\ninterface IExpandState {\r\n componentOpen: boolean //parent component\r\n groupOpen: boolean[] //small components in parent component\r\n}\r\n\r\nconst reducer = (\r\n { componentOpen, groupOpen }: IExpandState,\r\n { type, value, index, totalGroup, defaultGroupOpen }: IExpandAction\r\n) => {\r\n switch (type) {\r\n case 'INIT_GROUP':\r\n const groups = new Array(totalGroup).fill(value)\r\n return { componentOpen, groupOpen: groups }\r\n case 'INIT_GROUP_WITH_DEFAULT_ARRAY':\r\n componentOpen = defaultGroupOpen.some((expanded) => expanded)\r\n return { componentOpen, groupOpen: defaultGroupOpen }\r\n case 'AFFECT_ALL':\r\n const newGroups = groupOpen?.fill(value)\r\n return { componentOpen: value, groupOpen: newGroups }\r\n case 'AFFECT_ONE':\r\n const i = index ?? 0\r\n groupOpen[i] = value\r\n if (value) {\r\n componentOpen = value\r\n } else if (groupOpen.every((o) => !o)) {\r\n componentOpen = false\r\n }\r\n return { componentOpen, groupOpen }\r\n default:\r\n return { componentOpen, groupOpen }\r\n }\r\n}\r\n\r\nexport const useExpand = (initState: IExpandState) => {\r\n const [state, dispatch] = useReducer(reducer, initState)\r\n const expandAction = useMemo(\r\n () => ({\r\n initGroup: ({ totalGroup, initValue }) => {\r\n dispatch({ type: 'INIT_GROUP', value: initValue, totalGroup })\r\n },\r\n initGroupWithDefaultArray: (defaultGroupOpen: boolean[]) => {\r\n dispatch({ type: 'INIT_GROUP_WITH_DEFAULT_ARRAY', defaultGroupOpen })\r\n },\r\n setExpand: (value, index?: number) => {\r\n index >= 0 ? dispatch({ type: 'AFFECT_ONE', value, index }) : dispatch({ type: 'AFFECT_ALL', value })\r\n }\r\n }),\r\n [dispatch]\r\n )\r\n\r\n return {\r\n state,\r\n action: expandAction\r\n }\r\n}\r\n","import { useRef, DependencyList, MutableRefObject, useLayoutEffect } from 'react'\r\nimport { useLocation } from 'react-router-dom'\r\n\r\ninterface IPosition {\r\n x: number\r\n y: number\r\n}\r\n\r\ninterface IScrollProps {\r\n prevPos: IPosition\r\n currPos: IPosition\r\n}\r\n\r\ntype ElementRef = MutableRefObject\r\n\r\nconst isBrowser = typeof window !== `undefined`\r\nconst zeroPosition = { x: 0, y: 0 }\r\n\r\nconst getClientRect = (element?: HTMLElement) => element?.getBoundingClientRect()\r\n\r\nconst getScrollPosition = ({\r\n element,\r\n useWindow,\r\n boundingElement\r\n}: {\r\n element?: ElementRef\r\n boundingElement?: ElementRef\r\n useWindow?: boolean\r\n}) => {\r\n if (!isBrowser) {\r\n return zeroPosition\r\n }\r\n\r\n if (useWindow) {\r\n return { x: window.scrollX, y: window.scrollY }\r\n }\r\n\r\n const targetPosition = getClientRect(element?.current || document.body)\r\n const containerPosition = getClientRect(boundingElement?.current)\r\n\r\n if (!targetPosition) {\r\n return zeroPosition\r\n }\r\n\r\n return containerPosition\r\n ? {\r\n x: (containerPosition.x || 0) - (targetPosition.x || 0),\r\n y: (containerPosition.y || 0) - (targetPosition.y || 0)\r\n }\r\n : { x: targetPosition.left, y: targetPosition.top }\r\n}\r\n\r\nexport const useScrollPosition = (\r\n effect: (props: IScrollProps) => void,\r\n deps?: DependencyList,\r\n element?: ElementRef,\r\n useWindow?: boolean,\r\n wait?: number,\r\n boundingElement?: ElementRef\r\n): void => {\r\n const position = useRef(getScrollPosition({ useWindow, boundingElement }))\r\n\r\n let throttleTimeout: number | null = null\r\n\r\n const callBack = () => {\r\n const currPos = getScrollPosition({ element, useWindow, boundingElement })\r\n effect({ prevPos: position.current, currPos })\r\n position.current = currPos\r\n throttleTimeout = null\r\n }\r\n const location = useLocation()\r\n\r\n useLayoutEffect(() => {\r\n callBack()\r\n }, [location.pathname])\r\n\r\n useLayoutEffect(() => {\r\n if (!isBrowser) {\r\n return undefined\r\n }\r\n\r\n const handleScroll = () => {\r\n if (wait) {\r\n if (throttleTimeout === null) {\r\n throttleTimeout = window.setTimeout(callBack, wait)\r\n }\r\n } else {\r\n callBack()\r\n }\r\n }\r\n\r\n if (boundingElement) {\r\n boundingElement.current?.addEventListener('scroll', handleScroll, { passive: true })\r\n } else {\r\n window.addEventListener('scroll', handleScroll, { passive: true })\r\n }\r\n\r\n return () => {\r\n if (boundingElement) {\r\n boundingElement.current?.removeEventListener('scroll', handleScroll)\r\n } else {\r\n window.removeEventListener('scroll', handleScroll)\r\n }\r\n\r\n if (throttleTimeout) {\r\n clearTimeout(throttleTimeout)\r\n }\r\n }\r\n }, deps)\r\n}\r\n\r\nuseScrollPosition.defaultProps = {\r\n deps: [],\r\n element: false,\r\n useWindow: false,\r\n wait: null,\r\n boundingElement: false\r\n}\r\n","import { Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const AcceptenceBody = styled.div`\r\n background-color: ${({ theme }) => theme.colors.backgroundText};\r\n margin-left: 2.4rem;\r\n margin-right: 2.4rem;\r\n margin-bottom: 2.4rem;\r\n flex: 1;\r\n font-size: 1.6rem;\r\n\r\n p {\r\n background: inherit !important;\r\n }\r\n\r\n span {\r\n font-family: inherit !important;\r\n font-size: inherit !important;\r\n }\r\n\r\n div:not([class]) {\r\n margin-left: 3rem;\r\n }\r\n\r\n .form-check {\r\n margin-left: 3rem;\r\n }\r\n\r\n .form-check-label {\r\n margin-left: 1rem;\r\n }\r\n\r\n input[type='checkbox'] {\r\n position: relative;\r\n }\r\n`\r\n\r\nexport const ContinueButton = styled(Button)`\r\n height: 3rem;\r\n font-size: 1.4rem;\r\n margin-top: 1rem;\r\n line-height: 0.5;\r\n width: 15rem;\r\n font-size: 1.6rem;\r\n`\r\n\r\nexport const DocumentList = styled.div`\r\n margin-left: 3rem;\r\n margin-top: 1rem;\r\n margin-bottom: 1rem;\r\n`\r\n\r\nexport const Document = styled.div`\r\n display: block;\r\n`\r\n","import styled from 'styled-components'\r\n\r\nexport const TermConditionBody = styled.div`\r\n background-color: ${({ theme }) => theme.colors.backgroundText};\r\n margin-left: 2.4rem;\r\n margin-right: 2.4rem;\r\n margin-bottom: 2.4rem;\r\n flex: 1;\r\n\r\n p {\r\n background: inherit !important;\r\n }\r\n\r\n span {\r\n font-family: inherit !important;\r\n font-size: inherit !important;\r\n }\r\n\r\n div:not([class]) {\r\n margin-left: 3rem;\r\n }\r\n`\r\n\r\nexport const Title = styled.h2`\r\n color: ${({ theme }) => theme.colors.primary};\r\n text-transform: uppercase;\r\n font-size: 30ps;\r\n margin-bottom: 1.2rem;\r\n`\r\n","import { acceptNews } from 'apis/userApis'\r\nimport { CONTINUE } from 'common/constants'\r\nimport { MultiLanguageCode } from 'common/languageCodes'\r\nimport { rmsAuthModel } from 'common/rmsGlobal'\r\nimport { HTMLText } from 'components/Share/HtmlText'\r\nimport parse from 'html-react-parser'\r\nimport _ from 'lodash'\r\nimport { Col, Form, Image, Row } from 'react-bootstrap'\r\nimport { useIntl } from 'react-intl'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { AcceptenceBody, ContinueButton, Document, DocumentList } from './AcceptenceTerm.styled'\r\nimport { Title } from '../pages/TermCondition.styled'\r\nimport shallow from 'zustand/shallow'\r\n\r\nexport const AcceptenceTerm = () => {\r\n const intl = useIntl()\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n\r\n const newsHandler = async (markAccept) => {\r\n let newsID = rmsAuthModel?.newsModel?.NewsID\r\n\r\n if (newsID && newsID !== -1) {\r\n await acceptNews(newsID, markAccept)\r\n window.location.reload()\r\n }\r\n }\r\n\r\n const requiresAccept = rmsAuthModel?.newsModel?.RequiresAcceptance\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n {rmsAuthModel?.newsModel?.newsDocuments?.map((x) => {\r\n let document: string[] = x.split('|')\r\n return (\r\n \r\n \r\n \r\n {document[1]}\r\n \r\n \r\n )\r\n })}\r\n \r\n {requiresAccept ? (\r\n \r\n \r\n \r\n newsHandler(true)}\r\n />\r\n \r\n \r\n
\r\n ) : (\r\n \r\n \r\n newsHandler(false)} size=\"lg\">\r\n {CONTINUE}\r\n \r\n \r\n
\r\n )}\r\n \r\n >\r\n )\r\n}\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledWarningModal = styled(Modal)<{ isAlert?: boolean }>`\r\n .modal-content {\r\n background-color: ${({ isAlert, theme }) => (isAlert ? theme.colors.dangerColor : '#fff')};\r\n color: ${({ isAlert, theme }) => (isAlert ? theme.colors.colorTextModal : theme.colors.defaultDealerDeactive)};\r\n font-size: 1.6rem;\r\n a {\r\n color: #c71444;\r\n :hover {\r\n color: #810d2c;\r\n }\r\n }\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n width: 98%;\r\n }\r\n\r\n @media (min-width: ${gridBreakPoints.xxl}) {\r\n width: 67rem;\r\n }\r\n }\r\n .modal-header {\r\n border-bottom: none;\r\n }\r\n .modal-body {\r\n text-align: left;\r\n padding-bottom: 3rem;\r\n }\r\n`\r\n","import React, { ComponentProps, PropsWithChildren, ReactNode, useState } from 'react'\r\nimport { Col, Container, Modal, Row } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledWarningModal } from './GenericMessageWarning.styled'\r\n\r\ninterface IGenericMessageWarning extends ComponentProps {}\r\n\r\nexport const DefaultNode = () => {\r\n const errorMessages = useGlobalStore((state) => state.errorMessages, shallow)\r\n return (\r\n \r\n \r\n {errorMessages['ShowGenericMessage']}
\r\n \r\n
\r\n )\r\n}\r\n\r\nconst GenericMessageWarning = ({ children, isAlert, ...props }: PropsWithChildren) => {\r\n const clearError = useGlobalStore((state) => state.clearError, shallow)\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n {children}\r\n \r\n \r\n )\r\n}\r\nexport default React.memo(GenericMessageWarning)\r\n","import { Col, Row } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\nimport { LeftFooterContainer } from './LoginLayout.styled'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport { assetFolders } from 'common/constants'\r\n\r\nexport const StyledMainNavItem = styled.div<{ assetFolder?: string }>`\r\n width: ${({ assetFolder }) => (assetFolder === assetFolders.Independent ? '25%' : '20%')};\r\n @media (max-width: ${gridBreakPoints.xl}) {\r\n width: 25%;\r\n }\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n width: 30%;\r\n margin-top: 1rem;\r\n }\r\n`\r\nexport const StyledFooter = styled.div<{ assetFolder?: string }>`\r\n background: ${({ theme }) => theme.footer.backgroundColor};\r\n font-size: 1.4rem;\r\n padding: 2.4rem 0 1.6rem;\r\n width: 100%;\r\n\r\n > .row {\r\n width: 100%;\r\n @media (min-width: ${gridBreakPoints.md}) {\r\n min-height: 21rem;\r\n }\r\n }\r\n\r\n nav {\r\n justify-content: flex-end;\r\n padding-left: 4rem;\r\n }\r\n\r\n .nav-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n justify-content: flex-start;\r\n }\r\n\r\n ul {\r\n list-style: none;\r\n padding-inline-start: 0;\r\n }\r\n\r\n a {\r\n color: ${({ theme }) => theme.footer.fontColor};\r\n text-decoration: none;\r\n }\r\n\r\n .subnav li {\r\n padding-top: 0.475rem;\r\n }\r\n\r\n .nav-link {\r\n padding: 0;\r\n }\r\n\r\n .more-section {\r\n text-align: end;\r\n width: 80%;\r\n position: absolute;\r\n right: 3rem;\r\n }\r\n`\r\n\r\nexport const StyledFooterRow = styled(Row)`\r\n margin: 0;\r\n`\r\nexport const StyledNavItem = styled.a`\r\n text-transform: uppercase;\r\n font-weight: 800;\r\n display: inline-block;\r\n margin-bottom: 1.5rem;\r\n`\r\nexport const StyledFooterNav = styled.li`\r\n margin-top: 0.4rem;\r\n`\r\n\r\nexport const StyledFooterLogout = styled.li`\r\n margin-top: 2.75rem;\r\n font-weight: 600;\r\n`\r\n\r\nexport const StyledLogoContainer = styled(Col)`\r\n align-self: flex-end;\r\n padding-right: 2.75rem;\r\n`\r\n\r\nexport const StyledSubNavSmallScreen = styled.div`\r\n ul {\r\n display: flex;\r\n justify-content: center;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n\r\n li {\r\n padding: 0 1rem;\r\n\r\n &:last-child {\r\n border-left: 0.1rem solid ${({ theme }) => theme.colors.fontColor};\r\n }\r\n }\r\n }\r\n`\r\nexport const LayoutLeftFooterContainer = styled(LeftFooterContainer)`\r\n color: #fff;\r\n display: flex;\r\n align-items: flex-end;\r\n padding-left: 2.75rem;\r\n font-size: 1.1rem;\r\n`\r\n\r\nexport const StyledFooterLogo = styled.div<{ assetFolder?: string }>`\r\n display: flex;\r\n justify-content: flex-end;\r\n text-align: end;\r\n transform: ${({ assetFolder }) =>\r\n (assetFolder === assetFolders.Nissan || assetFolder === assetFolders.Guest) && 'brightness(0) invert(1)'};\r\n padding-top: 2rem;\r\n > img {\r\n max-height: 5rem;\r\n filter: ${({ assetFolder }) =>\r\n (assetFolder === assetFolders.Nissan || assetFolder === assetFolders.Guest) && 'brightness(0) invert(1)'};\r\n }\r\n`\r\n\r\nexport const SeperatorFAQMenu = styled.hr`\r\n width: 80%;\r\n border-bottom: 0.01px solid rgb(153 149 149 / 50%);\r\n margin-bottom: 0;\r\n margin-right: 0;\r\n margin-left: auto;\r\n`\r\n\r\nexport const LogoutFooterListItem = styled.li`\r\n text-transform: uppercase;\r\n`\r\n","import { FAQ, FooterMenuExclusionList, LogoFooter, TERM_AND_CONDITION } from 'common/constants'\r\nimport { MultiLanguageCode } from 'common/languageCodes'\r\nimport { NavLink } from 'components/Share/Link'\r\nimport parse from 'html-react-parser'\r\nimport _ from 'lodash'\r\nimport { Col, Container, Row } from 'react-bootstrap'\r\nimport { useIntl } from 'react-intl'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { handlePortalMenuItemClick } from 'utils/menuUtils'\r\nimport shallow from 'zustand/shallow'\r\nimport {\r\n LayoutLeftFooterContainer,\r\n SeperatorFAQMenu,\r\n StyledFooter,\r\n StyledFooterLogo,\r\n StyledFooterRow,\r\n StyledLogoContainer,\r\n StyledMainNavItem,\r\n StyledNavItem,\r\n StyledSubNavSmallScreen,\r\n LogoutFooterListItem\r\n} from './Footer.styled'\r\n\r\nexport const Footer = () => {\r\n const [{ Menu: menu, IsSSO: isSSO }, getLocalText, assetFolder] = useGlobalStore(\r\n (state) => [state.userClaims, state.getLocalText, state.userClaims.CurrentBuyerTypeAssetFolder],\r\n shallow\r\n )\r\n const intl = useIntl()\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n - \r\n {TERM_AND_CONDITION}\r\n
\r\n - \r\n \r\n {parse(intl.formatMessage({ id: MultiLanguageCode.PRIVACY_POLICY_HEADER }))}\r\n \r\n
\r\n - \r\n \r\n {parse(intl.formatMessage({ id: MultiLanguageCode.CONTACT_US }))}\r\n \r\n
\r\n - \r\n {FAQ}\r\n
\r\n\r\n {!_.isNil(isSSO) && !isSSO && (\r\n <>\r\n \r\n \r\n {getLocalText && getLocalText('LOGOUT', 'Logout')}\r\n \r\n >\r\n )}\r\n - \r\n \r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n - \r\n {TERM_AND_CONDITION}\r\n
\r\n - \r\n FAQs\r\n
\r\n - \r\n \r\n {parse(intl.formatMessage({ id: MultiLanguageCode.CONTACT_US }))}\r\n \r\n
\r\n {!_.isNil(isSSO) && !isSSO && (\r\n \r\n {getLocalText && getLocalText('LOGOUT', 'Logout')}\r\n \r\n )}\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","function BurgerButton(props) {\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport default BurgerButton\r\n","import React, { useContext } from 'react'\r\nimport BurgerIcon from 'images/icon/BurgerIcon'\r\nimport { LayoutContext } from 'contexts/LayoutContext'\r\nimport { StyledBurgerButton } from './Layout.styled'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\n\r\ninterface IProps {\r\n isSticky?: boolean\r\n}\r\nconst BurgerButton = ({ isSticky }: IProps) => {\r\n const { setShowMenuSidebar } = useContext(LayoutContext)\r\n const { userInteraction } = useDtmAnalytics()\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport default BurgerButton\r\n","import { IconProps } from 'core/typing/IconType'\r\nimport { useTheme } from 'styled-components'\r\n\r\nexport const AdvanceSearchIcon = () => {\r\n const theme = useTheme()\r\n return (\r\n \r\n )\r\n}\r\n","export const SaveSearchIcon = () => {\r\n return (\r\n \r\n )\r\n}\r\n","export const CurrentBidIcon = () => {\r\n return (\r\n \r\n )\r\n}\r\n","export const RDP_AccountSettingIcon = () => {\r\n return (\r\n \r\n )\r\n}\r\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport {\r\n faSearch,\r\n faList,\r\n faPhone,\r\n faUser,\r\n faSignOutAlt,\r\n faQuestionCircle,\r\n faLaptop,\r\n faCarSide,\r\n faHouseUser\r\n} from '@fortawesome/free-solid-svg-icons'\r\nimport { IconSvg } from '@prism/icon'\r\nimport { AdvanceSearchIcon } from '../images/icon/AdvanceSearchIcon'\r\nimport { SaveSearchIcon } from 'images/icon/SaveSearchIcon'\r\nimport { CurrentBidIcon } from 'images/icon/CurrentBidIcon'\r\nimport { RDP_AccountSettingIcon } from 'images/icon/AccountSettingIcon'\r\n\r\nexport const iconDict = {\r\n RDP_MyDashboard: ,\r\n RDP_News: ,\r\n RDP_GroundVehicle: ,\r\n RDP_SearchResults: ,\r\n RDP_SearchResults_2: ,\r\n RDP_AdvancedSearch: ,\r\n RDP_SavedSearch: ,\r\n RDP_WatchList: ,\r\n RDP_CurrentBids: ,\r\n RDP_WatchList_2: ,\r\n RDP_CurrentBids_2: ,\r\n RDP_MyProfile: ,\r\n RDP_ContactUs: ,\r\n RDP_ManageUsers: ,\r\n RDP_AccountSettings: ,\r\n RDP_ManageDevices: ,\r\n FAQ: ,\r\n Logout: \r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\n\r\nconst Person = (props) => (\r\n \r\n \r\n \r\n)\r\n\r\nexport default Person\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledUserMenu = styled.div<{ show: boolean; isSticky: boolean; assetFolder: string }>`\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n /* display: flex;\r\n flex-direction: column; */\r\n align-items: end;\r\n padding: 0 1.825rem 0;\r\n\r\n .username {\r\n font-size: 1.3rem;\r\n font-weight: 600;\r\n display: flex;\r\n align-items: center;\r\n //gap: 1rem;\r\n color: ${({ isSticky, assetFolder, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.userMenuFont\r\n }\r\n return theme.headerNotSticky.userMenuFont\r\n }};\r\n svg {\r\n display: inline-block;\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: ${({ show }) => (show ? 'flex' : 'none')};\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n`\r\n\r\nexport const StyledDealerDropdown = styled.div`\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n font-size: 1.4rem;\r\n cursor: pointer;\r\n\r\n .current-user {\r\n display: flex;\r\n justify-content: space-between;\r\n flex-direction: column;\r\n align-items: center;\r\n }\r\n\r\n .current-user::after {\r\n display: none;\r\n }\r\n .dealership-select.dropdown-menu {\r\n box-shadow: 0 0.3rem 0.4rem rgba(0, 0, 0, 0.15);\r\n font-size: inherit;\r\n border: none;\r\n border-radius: 0.3rem;\r\n padding: 0;\r\n display: block;\r\n transition: all 167ms ease-in;\r\n transform: translate(0.0015625rem, 6.2rem);\r\n inset: 0 0 auto auto !important;\r\n\r\n &.show {\r\n opacity: 1;\r\n }\r\n\r\n hr {\r\n margin: 0;\r\n }\r\n\r\n .associated-dealerships {\r\n max-height: 50rem;\r\n overflow: auto;\r\n }\r\n }\r\n .dealership-item {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n font-weight: 600;\r\n height: 2.5rem;\r\n display: flex;\r\n align-items: center;\r\n transition: all 167ms ease-in;\r\n position: relative;\r\n background-color: transparent;\r\n\r\n svg {\r\n visibility: hidden;\r\n margin-right: 1rem;\r\n }\r\n &:hover,\r\n &.active,\r\n &.show-icon {\r\n svg {\r\n visibility: visible;\r\n }\r\n }\r\n\r\n &.functionality {\r\n height: auto;\r\n margin: 0.625rem 0;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledCurrentDealership = styled.div`\r\n /* padding-left: 2rem;\r\n padding-right: 1.825rem;\r\n text-align: right; */\r\n font-weight: bold;\r\n //color: ${({ theme }) => theme.colors.fontColor};\r\n`\r\n\r\nexport const RightActionContainer = styled.div<{ show: boolean }>`\r\n display: flex;\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: ${({ show }) => (show ? 'flex' : 'none')};\r\n flex-direction: column;\r\n align-items: center;\r\n\r\n & > div.nav {\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n\r\n .nav-item {\r\n width: 100%;\r\n border-top: 0.1rem solid ${({ theme }) => theme.colors.secondary};\r\n border-bottom: 0.1rem solid ${({ theme }) => theme.colors.secondary};\r\n\r\n &:hover > .nav-link {\r\n background-color: white;\r\n }\r\n\r\n > .nav-link {\r\n font-size: 1.8rem;\r\n height: 4rem;\r\n margin: unset;\r\n text-align: center;\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n }\r\n &.active {\r\n background: #d4d4d4;\r\n :after {\r\n content: none;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n & > div.nav {\r\n .nav-link {\r\n justify-content: center;\r\n font-size: 1.6rem;\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n padding: 0.8rem 0;\r\n margin-right: 1.5rem;\r\n }\r\n }\r\n`\r\n","import { faQuestionCircle } from '@fortawesome/free-regular-svg-icons'\r\nimport { faCheck, faPlus } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { setBuyer } from 'apis/serviceApis'\r\nimport { iconDict } from 'common/menuIcons'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport ChevronDown from 'icons/ChevronDown'\r\nimport Person from 'icons/Person'\r\nimport { useEffect, useMemo, useState } from 'react'\r\nimport { Dropdown, Nav } from 'react-bootstrap'\r\nimport { Link } from 'react-router-dom'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IPortalMenuResponse } from 'types/userTypes'\r\nimport { handlePortalMenuItemClick } from 'utils/menuUtils'\r\nimport shallow from 'zustand/shallow'\r\n\r\nimport { RightActionContainer, StyledCurrentDealership, StyledDealerDropdown, StyledUserMenu } from './UserMenu.styled'\r\n\r\ninterface IProps {\r\n showInMobile: boolean\r\n isSticky: boolean\r\n assetFolder: string\r\n}\r\n\r\nexport const UserMenu = (props: IProps) => {\r\n const {\r\n userClaims: {\r\n Username: userName,\r\n DealershipName: dealerShipName,\r\n AssociatedBuyers: associatedBuyers,\r\n IsSSO: isSSO,\r\n Menu: menu\r\n },\r\n isInRule\r\n } = useGlobalStore(\r\n (state) => ({\r\n userClaims: state.userClaims,\r\n isInRule: state.isInRule\r\n }),\r\n shallow\r\n )\r\n\r\n // TODO: Use ID instead of name\r\n const dealer = associatedBuyers?.find((item) => item.Description === dealerShipName)\r\n const [currentBuyerId, setCurrentBuyerId] = useState(dealer?.ID)\r\n const [userFunctionalities, setUserFunctionalities] = useState()\r\n const [isLoading, setIsLoading] = useState(false)\r\n const isOveUser = useMemo(() => isInRule('OVE Colisting'), [])\r\n useEffect(() => {\r\n const logoutLink: IPortalMenuResponse = {\r\n MenuItem: {\r\n ID: 0,\r\n Text: 'Logout',\r\n URL: '/logout',\r\n Name: 'Logout',\r\n OrderNo: 0,\r\n ParentName: ''\r\n },\r\n URL: '/logout',\r\n IsWebMenu: true,\r\n Children: []\r\n }\r\n const myAccountLink = menu?.Children.map((m) => m.Children)\r\n .flat()\r\n .find((m) => m.MenuItem.Name === 'RDP_MyProfile')\r\n setUserFunctionalities([myAccountLink, logoutLink])\r\n }, [menu])\r\n\r\n const handleChangeCurrentBuyer = async (value: any) => {\r\n // If user select the same buyer, we won't need to do anything\r\n if (currentBuyerId === value || value === 'Logout') return\r\n\r\n try {\r\n setIsLoading(true)\r\n setCurrentBuyerId(value)\r\n await setBuyer(value)\r\n window.location.reload()\r\n } catch (err) {\r\n console.error(err)\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n if (!menu) {\r\n return null\r\n }\r\n\r\n return (\r\n \r\n \r\n {isLoading && }\r\n\r\n \r\n handleChangeCurrentBuyer(value as never)}\r\n >\r\n \r\n \r\n
\r\n
\r\n {userName}\r\n \r\n {dealerShipName} \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n {associatedBuyers.map((item) => (\r\n \r\n \r\n {item.Description}\r\n \r\n ))}\r\n
\r\n {!isSSO && (\r\n \r\n
\r\n {isOveUser && (\r\n \r\n \r\n {'Add Dealership(s)'}\r\n \r\n )}\r\n {userFunctionalities?.map(\r\n (item) =>\r\n !!item && (\r\n handlePortalMenuItemClick(item)}\r\n >\r\n {iconDict[item.MenuItem.Name]}\r\n {item.MenuItem.Text}\r\n \r\n )\r\n )}\r\n
\r\n )}\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { postAsync } from 'common/fetch'\r\n\r\nexport const setBuyer = (id: number) => {\r\n return postAsync(`/service/setbuyer?id=${id}`)\r\n}\r\n","import { iconDict } from 'common/menuIcons'\r\nimport { NavLink } from 'components/Share/Link'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\nimport { resetSRPFilter } from 'utils/menuUtils'\r\nimport { IPortalMenuResponse } from '../types/userTypes'\r\nimport { StyledSubMenu, StyledSubMenuItem } from './SubMenu.styled'\r\ninterface IProps {\r\n isSticky?: boolean\r\n assetFolder?: string\r\n items: IPortalMenuResponse[]\r\n onClick?: () => void\r\n}\r\n\r\nexport const SubMenu = ({ items, onClick, isSticky, assetFolder }: IProps) => {\r\n const handleSubMenuClick = (e: any) => {\r\n onClick?.()\r\n resetSRPFilter()\r\n setCustomClick(`Ham menu: ${e.target.textContent.trim()}`)\r\n }\r\n\r\n return (\r\n \r\n {items.map((item) => (\r\n \r\n {item.URL && (\r\n \r\n {iconDict[item.MenuItem.Name]}\r\n {item.MenuItem.Text}\r\n \r\n )}\r\n \r\n ))}\r\n \r\n )\r\n}\r\n","/* eslint-disable no-script-url */\r\nimport { MenuExclusionList } from 'common/constants'\r\nimport { NavLink } from 'components/Share/Link'\r\nimport { LayoutContext } from 'contexts/LayoutContext'\r\nimport { useContext } from 'react'\r\nimport { Nav } from 'react-bootstrap'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\nimport shallow from 'zustand/shallow'\r\n\r\nimport { IPortalMenuResponse } from '../types/userTypes'\r\nimport { StyledCloseMenuButton, StyledMainNav, StyledNavBar, StyledUnderlineSpan } from './NavBar.styled'\r\nimport { UserMenu } from './UserMenu'\r\nimport { SubMenu } from './SubMenu'\r\nimport { resetSRPFilter } from 'utils/menuUtils'\r\n\r\nconst isActiveItem = (item: IPortalMenuResponse, pathname: string): boolean => {\r\n if (item.URL && (item.URL === pathname || item.URL.slice(2) === pathname)) {\r\n return true\r\n }\r\n return Boolean(item.Children?.find((child) => isActiveItem(child, pathname)))\r\n}\r\ninterface IProps {\r\n isSticky?: boolean\r\n assetFolder?: string\r\n}\r\n\r\nexport const NavBar = ({ isSticky, assetFolder }: IProps) => {\r\n const { pathname } = useLocation()\r\n const { showMenuSidebar, setShowMenuSidebar } = useContext(LayoutContext)\r\n const [isTerm, menu] = useGlobalStore((state) => [state.userClaims.IsTermAccepted, state.userClaims.Menu], shallow)\r\n\r\n const handleMenuClick = (e: any) => {\r\n resetSRPFilter()\r\n setCustomClick(`Tab Menu: ${e.target.textContent.trim()}`)\r\n }\r\n\r\n return (\r\n \r\n \r\n setShowMenuSidebar(false)}>x\r\n \r\n \r\n \r\n )\r\n}\r\n","import classNames from 'classnames'\r\nimport { assetFolders, vendorImages } from 'common/constants'\r\nimport { NavLink } from 'components/Share/Link'\r\nimport { LayoutContext } from 'contexts/LayoutContext'\r\nimport { useContext } from 'react'\r\nimport Image from 'react-bootstrap/Image'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport BurgerButton from './BurgerButton'\r\nimport { StyledBranding, StyledHeader } from './Layout.styled'\r\nimport { NavBar } from './NavBar'\r\nimport { UserMenu } from './UserMenu'\r\n\r\ninterface IProps {\r\n enableSticky?: boolean\r\n className?: string\r\n}\r\n\r\nconst GetLogoURL = (assetFolder, isSticky) => {\r\n let url = isSticky\r\n ? assetFolder !== assetFolders.Independent\r\n ? vendorImages.whiteLogo\r\n : vendorImages.rightLogo\r\n : vendorImages.rightLogo\r\n if (assetFolder === undefined) {\r\n return url.replace('/{assetFolder}', '')\r\n }\r\n return url.replace('{assetFolder}', assetFolder)\r\n}\r\n\r\nexport const Header = ({ enableSticky = false, className }: IProps) => {\r\n const { isSticky: sticky } = useContext(LayoutContext)\r\n const [isAuthenticated, assetFolder] = useGlobalStore((state) => [\r\n state.isAuthenticated,\r\n state.userClaims.CurrentBuyerTypeAssetFolder\r\n ])\r\n\r\n let isSticky = sticky && enableSticky\r\n\r\n if (!assetFolder) {\r\n isSticky = false\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n {isAuthenticated && }\r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport const HeaderParent = () => {\r\n return (\r\n <>\r\n \r\n \r\n >\r\n )\r\n}\r\n","import { LayoutContext } from 'contexts/LayoutContext'\r\nimport { useScrollPosition } from 'hooks/useScrollPosition'\r\nimport { AcceptenceTerm } from 'modules/AcceptenceTerm'\r\nimport GenericMessageWarning, { DefaultNode } from 'modules/GenericMessageWarning'\r\nimport { ReactNode, useContext, useMemo, useState } from 'react'\r\nimport { Helmet } from 'react-helmet'\r\nimport { Link, useLocation } from 'react-router-dom'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport shallow from 'zustand/shallow'\r\n\r\nimport { Button, Col, Row } from 'react-bootstrap'\r\nimport { ISystemSetting } from 'types/baseTypes'\r\nimport { Footer } from './Footer'\r\nimport { HeaderParent } from './Header'\r\nimport { StyledBody, StyledLayout } from './Layout.styled'\r\n\r\ninterface IProps {\r\n title?: string\r\n children: ReactNode\r\n}\r\n\r\nexport const Layout = ({ title, children }: IProps) => {\r\n const [userClaims, isAuthenticated, errorMessages, getSystemSettings] = useGlobalStore(\r\n (state) => [state.userClaims, state.isAuthenticated, state.errorMessages, state.getSystemSetting],\r\n shallow\r\n )\r\n const { setIsSticky } = useContext(LayoutContext)\r\n\r\n const isShowFooter = useMemo(\r\n () => ((userClaims.IsTermAccepted && userClaims.Username) || !userClaims.Username ? true : false),\r\n [userClaims.IsTermAccepted, userClaims.Username]\r\n )\r\n\r\n const url = getSystemSettings('AUCTION_ACCESS_URL') as ISystemSetting\r\n const [isOpen, setIsOpen] = useState(true)\r\n const renderErrorMessage = (key: string, value: string): ReactNode => {\r\n switch (key) {\r\n case 'ShowGenericMessage':\r\n return \r\n case 'ShowAuctionACCESSMessage':\r\n return (\r\n <>\r\n \r\n \r\n {value}
\r\n \r\n
\r\n \r\n \r\n window.open(url.ValueString, '_blank')} to=\"#\">\r\n Click here\r\n {' '}\r\n to register and enable your access\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n >\r\n )\r\n default:\r\n return <>>\r\n }\r\n }\r\n const location = useLocation()\r\n\r\n useScrollPosition(\r\n ({ currPos }) => {\r\n const headerHeight = document.querySelector('.main-nav')?.offsetHeight\r\n if (currPos.y <= -headerHeight) {\r\n setIsSticky(true)\r\n } else {\r\n setIsSticky(false)\r\n }\r\n },\r\n [location.pathname]\r\n )\r\n\r\n return (\r\n \r\n \r\n {title}\r\n \r\n \r\n {isAuthenticated && !userClaims.IsTermAccepted ? : children}\r\n {isShowFooter && }\r\n {errorMessages &&\r\n Object.entries(errorMessages).map(([key, value]) => (\r\n {renderErrorMessage(key, value)}\r\n ))}\r\n \r\n )\r\n}\r\n","import { useState, useEffect } from 'react'\r\nimport { useInterval } from './useInterval'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { secondsDiff } from 'utils/dateUtils'\r\n\r\nexport const useCountdown = (endDate: Date | string) => {\r\n const { serverTime, clientTime } = useGlobalStore()\r\n\r\n const [seconds, setSeconds] = useState(secondsDiff(serverTime, clientTime, new Date(endDate)))\r\n const [delay, setDelay] = useState(endDate ? 1000 : null)\r\n\r\n useEffect(() => {\r\n if (endDate) {\r\n setDelay(1000)\r\n } else {\r\n setDelay(null)\r\n }\r\n }, [endDate])\r\n useInterval(() => {\r\n const diff = secondsDiff(serverTime, clientTime, new Date(endDate))\r\n\r\n if (diff > 0) {\r\n setSeconds(diff)\r\n } else {\r\n setSeconds(0)\r\n setDelay(null)\r\n }\r\n }, delay)\r\n\r\n return {\r\n seconds\r\n }\r\n}\r\n","import { useEffect, useRef } from 'react'\r\n\r\nexport const useInterval = (callback: () => void, delay: number | null) => {\r\n const savedCallback = useRef(callback)\r\n\r\n // Remember the latest callback if it changes.\r\n useEffect(() => {\r\n savedCallback.current = callback\r\n }, [callback])\r\n\r\n // Set up the interval.\r\n useEffect(() => {\r\n // Don't schedule if no delay is specified.\r\n if (delay === null) {\r\n return\r\n }\r\n\r\n const id = setInterval(() => savedCallback.current(), delay)\r\n\r\n return () => clearInterval(id)\r\n }, [delay])\r\n}\r\n","import { IContactReason, IContactUsData } from './../types/contactTypes'\r\nimport { IVendorInfo } from 'types/rmsGlobalTypes'\r\nimport { apiRootPath, fetchAsync, postAsync } from 'common/fetch'\r\nimport { IBuyerAuthorizationResponse, ISecretQuestionResponse } from 'types/rmsAuthModel'\r\nimport { toUrlSearchParams } from 'utils/urlParams'\r\nimport { IUserClaimReponse } from 'types/userTypes'\r\nimport { IContactUsReponse } from 'types/contactTypes'\r\nimport { IAddressRequest } from 'types/accountTypes'\r\n\r\nexport const login = (username: string, password: string) => {\r\n const loginData = {\r\n grant_type: 'password',\r\n username: username,\r\n password: password\r\n }\r\n return postAsync<{ access_token: string; isFirstLogin: string }>('/token', {\r\n body: new URLSearchParams(loginData).toString(),\r\n type: 'form-data'\r\n })\r\n}\r\n\r\nexport const validateBuyer = () => {\r\n return postAsync(`${apiRootPath}/auth/validatebuyer`)\r\n}\r\n\r\nexport const getSecretQuestion = (username: string) => {\r\n return fetchAsync(`${apiRootPath}/account/getsecretquestion?username=${username}`)\r\n}\r\nexport const sendPasswordReset = (username: string, answer: string, questionId: number) => {\r\n const passwordReset = {\r\n username: username,\r\n answer: answer,\r\n questionCode: questionId\r\n }\r\n return fetchAsync(`${apiRootPath}/account/sendpasswordreset?${toUrlSearchParams(passwordReset)}`)\r\n}\r\n\r\nexport const getUserClaims = () => {\r\n return fetchAsync(`${apiRootPath}/user/claims`)\r\n}\r\n\r\nexport const getCsrfToken = () => {\r\n return fetchAsync(`${apiRootPath}/auth/csrftoken`)\r\n}\r\n\r\nexport const acceptNews = async (newsID: number, markAccept: boolean) => {\r\n return fetchAsync(`/api/v1/account/acceptNews?ID=${newsID}&markAsAccept=${markAccept}`)\r\n}\r\n\r\nexport const getContactUsDropDown = async (vendorId: number) => {\r\n return fetchAsync(`/api/dashboard/GetContactUsDropDowns?vendorId=${vendorId}`)\r\n}\r\n\r\nexport const getValidatedVin = async (vendorId: number, vin: string) => {\r\n return postAsync(`/api/dashboard/GetValidatedVin?vendorId=${vendorId}&vin=${vin}`)\r\n}\r\n\r\nexport const sendContactUsEmail = async (request: IContactUsData) => {\r\n return postAsync(`/api/dashboard/SendContactUsEmail`, { body: request })\r\n}\r\n\r\nexport const saveAddress = async (request: IAddressRequest) => {\r\n return postAsync(`${apiRootPath}/account/SaveAddress`, {\r\n body: request\r\n })\r\n}\r\n\r\nexport const saveAuctionAccessPrefrence = async () => {\r\n return postAsync(`/service/hideAuctionAccessMessage?showMessage=false`)\r\n}\r\n","import { assetFolders, zIndex } from 'common/constants'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport styled, { css, keyframes } from 'styled-components'\r\nimport { StyledMainNav, StyledNavBar } from './NavBar.styled'\r\n\r\nexport interface StickyProp {\r\n isSticky?: boolean\r\n assetFolder?: string\r\n}\r\nexport const StyledLayout = styled.div`\r\n display: flex;\r\n flex-direction: column;\r\n min-height: 100vh;\r\n`\r\n\r\nexport const StyledHeader = styled.div`\r\n width: 100%;\r\n height: ${({ isSticky }) => (isSticky ? '5rem' : '10rem')};\r\n background-color: ${({ isSticky, theme }) => (isSticky ? theme.colors.primary : null)};\r\n ${({ isSticky, assetFolder }) =>\r\n isSticky &&\r\n css`\r\n top: 0;\r\n z-index: ${zIndex.stickyHeader};\r\n max-height: 5rem;\r\n background-color: ${({ theme }) => {\r\n return theme.headerSticky.backgroundColor\r\n }};\r\n `}\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n ${({ isSticky }) => (isSticky ? headerAnimation : null)};\r\n border-bottom: 0.1rem solid ${({ theme }) => theme.colors.secondary};\r\n`\r\n\r\nconst curtainEffect = keyframes`\r\n from {\r\n transform: translateY(-15rem);\r\n }\r\n`\r\nexport const headerAnimation = css`\r\n animation: ${curtainEffect} 0.6s ease-in-out;\r\n`\r\nexport const StyledBranding = styled.div`\r\n display: flex;\r\n // justify-content: space-between;\r\n align-items: center;\r\n // flex-grow: 1;\r\n max-height: 12rem;\r\n height: 100%;\r\n padding-left: 2.75rem;\r\n ${({ assetFolder }) =>\r\n assetFolder === assetFolders.Infiniti &&\r\n css`\r\n padding-left: 0;\r\n `}\r\n a {\r\n height: 100%;\r\n }\r\n\r\n img {\r\n height: 7rem;\r\n transform: translateY(1.1rem);\r\n\r\n ${({ assetFolder }) => {\r\n switch (assetFolder) {\r\n case assetFolders.Nissan:\r\n return css`\r\n transform: translateY(1.1rem) translateX(0.7rem);\r\n `\r\n case assetFolders.Infiniti:\r\n return css`\r\n transform: translateY(1.5rem) translateX(0.6rem);\r\n `\r\n case assetFolders.Independent:\r\n return css`\r\n height: 9rem;\r\n transform: translateY(0.3rem) translateX(0.6rem);\r\n `\r\n default:\r\n return css`\r\n transform: translateX(0.7rem);\r\n `\r\n }\r\n }}\r\n\r\n ${({ isSticky, assetFolder }) => {\r\n if (isSticky) {\r\n switch (assetFolder) {\r\n case assetFolders.Nissan:\r\n return css`\r\n height: 90%;\r\n transform: translateY(0.3rem) translateX(0.6rem);\r\n `\r\n case assetFolders.Infiniti:\r\n return css`\r\n height: 8rem;\r\n transform: translateY(-2rem) translateX(1.1rem);\r\n `\r\n case assetFolders.Independent:\r\n return css`\r\n height: 5.5rem;\r\n transform: translateY(-0.7rem) translateX(0.4rem);\r\n `\r\n default:\r\n return null\r\n }\r\n }\r\n }}\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n border-bottom: unset;\r\n }\r\n\r\n ${({ isSticky }) =>\r\n isSticky\r\n ? css`\r\n border-bottom: none;\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n justify-content: center;\r\n }\r\n `\r\n : css`\r\n //padding: 2.75rem 2.75rem 1.75rem;\r\n /* border-bottom: 0.1rem solid ${({ theme }) => theme.colors.secondary}; */\r\n `}\r\n`\r\nexport const StyledMenuHeader = styled.div.attrs({\r\n className: 'container-fluid'\r\n})`\r\n font-family: ${({ theme }) => theme.fonts.fontRegular};\r\n display: flex;\r\n justify-content: space-between;\r\n padding: 0 3rem;\r\n\r\n @media (min-width: ${gridBreakPoints.lg}) {\r\n ${StyledNavBar} {\r\n ${StyledMainNav} {\r\n .nav .nav-item:first-child > .nav-link {\r\n padding-left: 0;\r\n margin-left: 0;\r\n }\r\n }\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n position: absolute;\r\n top: 0;\r\n }\r\n`\r\n\r\nexport const StyledBody = styled.div`\r\n flex-grow: 1;\r\n`\r\n\r\nexport const StyledBurgerButton = styled.div`\r\n width: 3.6rem;\r\n height: 3.6rem;\r\n display: none;\r\n margin-right: 2rem;\r\n\r\n z-index: 100;\r\n button {\r\n width: 100%;\r\n height: 100%;\r\n border: none;\r\n background-color: transparent;\r\n svg {\r\n fill: ${({ isSticky }) => (isSticky ? '#e5e6e4' : 'rgba(0, 0, 0, 0.2)')};\r\n }\r\n &:hover > svg {\r\n transition: all 200ms ease-in;\r\n fill: ${({ isSticky }) => (isSticky ? '#fff' : 'rgba(0, 0, 0, 0.5)')};\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: block;\r\n }\r\n`\r\n","import { borderColorSecondary } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledDropdownList = styled.div`\r\n & {\r\n user-select: none;\r\n background-color: white;\r\n }\r\n\r\n &:hover {\r\n cursor: pointer;\r\n }\r\n\r\n .dropdown:focus,\r\n .dropdown:focus-visible,\r\n .dropdown:hover {\r\n background-color: #fff;\r\n outline: 0;\r\n box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n\r\n .dropdown-title {\r\n border-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n }\r\n\r\n .dropdown-title {\r\n color: rgba(0, 0, 0, 0.5);\r\n font-weight: 600;\r\n width: 100%;\r\n text-align: left;\r\n background-color: white;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n overflow: hidden;\r\n font-size: 1.4rem;\r\n\r\n /* Keep the number equal bootstrap's default number */\r\n height: calc(1.5em + 0.75rem + 2px);\r\n padding: 0.5rem 0.75rem;\r\n border-radius: 0.25rem;\r\n border: 1px solid ${borderColorSecondary};\r\n }\r\n\r\n .dropdown-title:focus-visible {\r\n border-color: #53afff;\r\n background-color: #fff;\r\n outline: 0;\r\n box-shadow: 0 0 0 0.2rem rgb(0 112 210 / 25%);\r\n }\r\n\r\n .dropdown-title:after {\r\n display: none;\r\n }\r\n\r\n .dropdown-select {\r\n padding-bottom: 0px;\r\n min-width: 100%;\r\n font-size: 1.4rem;\r\n }\r\n\r\n .dropdown-item {\r\n font-weight: 600;\r\n font-size: 1.4rem;\r\n display: flex;\r\n align-items: center;\r\n color: rgba(0, 0, 0, 0.5);\r\n background-color: transparent;\r\n transition: all 167ms ease-in;\r\n position: relative;\r\n border-bottom: 2px solid white;\r\n }\r\n\r\n .dropdown-item.active,\r\n .dropdown-item:focus-visible,\r\n .dropdown-item:hover {\r\n outline: 0;\r\n border-bottom: 2px solid ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n`\r\n","import { useEffect, useState } from 'react'\r\nimport { Dropdown } from 'react-bootstrap'\r\nimport { StyledDropdownList } from './DropdownList.styled'\r\nimport ChevronDown from 'icons/ChevronDown'\r\n\r\ninterface IProps {\r\n defaultValue: string\r\n items: IDropDownItemProps[]\r\n onChange?: (value) => void\r\n}\r\n\r\ninterface IDropDownItemProps {\r\n id: string\r\n value: string\r\n}\r\n\r\nexport const DropdownList = ({ defaultValue, items, onChange }: IProps) => {\r\n const [currentValue, setCurrentValue] = useState('')\r\n\r\n useEffect(() => {\r\n setCurrentValue(defaultValue)\r\n }, [defaultValue])\r\n\r\n const handleSelectChange = (id) => {\r\n setCurrentValue(id)\r\n onChange?.(id)\r\n }\r\n\r\n return (\r\n \r\n handleSelectChange(id)}>\r\n handleSelectChange(id)}\r\n className=\"dropdown-title\"\r\n tabIndex={0}\r\n >\r\n {items.find((i) => i.id === currentValue)?.value ?? 'Select'}\r\n \r\n \r\n \r\n {items.map((item) => (\r\n \r\n {item.value}\r\n \r\n ))}\r\n \r\n \r\n \r\n )\r\n}\r\n","import loglevel from 'loglevel'\r\n\r\nif (process.env.NODE_ENV === 'development') {\r\n loglevel.setLevel('info')\r\n}\r\n\r\nexport const log = loglevel\r\nexport default log\r\n","import { DateTime } from 'luxon'\r\n\r\nexport function formatDate(date: string, format: string) {\r\n return DateTime.fromISO(date).toFormat(format)\r\n}\r\n\r\nexport const secondsDiff = (serverTime: Date, clientTime: Date, saleEndDate: Date) => {\r\n const adjustTime = serverTime.getTime() + (new Date().getTime() - clientTime.getTime())\r\n return Math.round((saleEndDate.getTime() - adjustTime) / 1000)\r\n}\r\n\r\nexport const getNextDate = (day): Date => {\r\n var nextdate = new Date(day)\r\n return new Date(nextdate.setDate(nextdate.getDate() + 1))\r\n}\r\n\r\nexport const addMonths = (date: Date, months: number) => {\r\n const newDate = new Date(date)\r\n newDate.setMonth(newDate.getMonth() + months)\r\n return newDate\r\n}\r\n\r\nexport const addDays = (date: Date, days: number) => {\r\n const newDate = new Date(date)\r\n newDate.setDate(newDate.getDate() + days)\r\n return newDate\r\n}\r\n\r\n// export const getVendorTime = (date: Date, timeZoneRegistryID) => {\r\n// const timeZone = findIana(timeZoneRegistryID)?.[0]\r\n// return new Date(\r\n// date.toLocaleString('en-US', {\r\n// timeZone\r\n// })\r\n// )\r\n// }\r\n","export const ArrowDown = (props) => (\r\n \r\n)\r\n","export const ArrowUp = (props) => (\r\n \r\n)\r\n","import { extraLargeScreen, largeScreen, smallScreen } from 'common/theme'\r\nimport { Popover } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nconst minWidth = '20rem'\r\n\r\nexport const StyledSort = styled.div`\r\n & {\r\n display: flex;\r\n align-items: center;\r\n }\r\n .sort-label {\r\n font-weight: 600;\r\n margin-right: 0.3rem;\r\n\r\n display: inline-block;\r\n @media (max-width: ${extraLargeScreen}) {\r\n display: none;\r\n }\r\n }\r\n\r\n .btn-current-sort {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 0.5rem;\r\n\r\n font-size: 1.6rem;\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n\r\n background: none;\r\n border: none;\r\n }\r\n\r\n .btn.btn-current-sort:hover,\r\n .btn.btn-current-sort:focus,\r\n .btn.btn-current-sort:active {\r\n color: ${({ theme }) => theme.colors.primaryDarken};\r\n background: none;\r\n border: none;\r\n box-shadow: none;\r\n }\r\n\r\n @media (max-width: ${smallScreen}) {\r\n display: inline-flex;\r\n }\r\n\r\n @media (max-width: ${largeScreen}) {\r\n float: right;\r\n align-items: center;\r\n }\r\n`\r\nexport const StyledSortPopover = styled(Popover)`\r\n & {\r\n min-width: ${minWidth};\r\n }\r\n .sort-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n\r\n margin-top: 1.2rem;\r\n font-size: 1.5rem;\r\n }\r\n\r\n .btn-sort {\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n\r\n .sort-button-group .btn-sort.active {\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n color: white;\r\n }\r\n`\r\n","import { ArrowDown } from 'icons/ArrowDown'\r\nimport { ArrowUp } from 'icons/ArrowUp'\r\nimport { groupBy } from 'lodash'\r\nimport { useRef, useState, useEffect } from 'react'\r\nimport { Button, Overlay, Popover } from 'react-bootstrap'\r\nimport { ISortBy, SortOrder } from 'types/baseTypes'\r\n\r\nimport { StyledSort, StyledSortPopover } from './Sort.styled'\r\n\r\ninterface IProps {\r\n currentSort: ISortBy\r\n sortOptions: ISortBy[]\r\n onChange?: (selectedSort: ISortBy) => void\r\n}\r\n\r\nconst parseSortName = (sortName: string) => {\r\n return sortName?.slice(0, sortName.indexOf(' -')) // Remove ' -' from option's name\r\n}\r\n\r\nexport const Sort = ({ currentSort: currentSortProp, sortOptions, onChange }: IProps) => {\r\n const [currentSort, setCurrentSort] = useState(currentSortProp)\r\n const [sortName, setSortName] = useState(currentSortProp?.Name ?? '')\r\n const [show, setShow] = useState(false)\r\n const sortRef = useRef(null)\r\n const containerRef = useRef(null)\r\n const sortFields = groupBy(\r\n sortOptions?.map((so) => ({ ...so, Name: parseSortName(so.Name) })),\r\n 'Name'\r\n )\r\n\r\n const handleSortChange = (sortValue: string) => {\r\n if (sortValue !== currentSort.Name) {\r\n const selectedSort = sortOptions.find((so) => so.Value === sortValue)\r\n setCurrentSort(selectedSort)\r\n setShow(false)\r\n onChange?.(selectedSort)\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n const name =\r\n currentSort.Name ??\r\n sortOptions?.find((o) => o.DBFieldName === currentSort.DBFieldName && o.Value === currentSort.Value)?.Name ??\r\n ''\r\n setSortName(name)\r\n }, [currentSort, sortOptions])\r\n\r\n return (\r\n <>\r\n {currentSort && (\r\n \r\n
\r\n Sort by\r\n \r\n \r\n
setShow(false)}\r\n show={show}\r\n placement=\"bottom\"\r\n transition={false}\r\n >\r\n \r\n \r\n {Object.keys(sortFields).map((sortFieldName) => (\r\n \r\n
{sortFieldName}
\r\n
\r\n {sortFields[sortFieldName].map((sortOption, i) => (\r\n
\r\n ))}\r\n
\r\n
\r\n ))}\r\n \r\n \r\n \r\n
\r\n )}\r\n >\r\n )\r\n}\r\n","import { Alert } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledUnwatchPlaceholderAlert = styled(Alert).attrs({\r\n variant: 'warning'\r\n})`\r\n min-height: 5rem;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.4rem;\r\n`\r\n\r\nexport const StyledAddWatchListSpan = styled.span`\r\n color: ${({ theme }) => theme.colors.linkColor};\r\n cursor: pointer;\r\n`\r\n\r\nexport const StyledRemovedWatchListPlaceHolder = styled.div``\r\n","import { VehicleDetailsView } from 'common/constants'\r\nimport { VehicleContext } from 'modules/DealerVehicleManagement/VehicleContext'\r\nimport { useMemo, useState, useContext } from 'react'\r\nimport { Col, Row, Spinner } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport shallow from 'zustand/shallow'\r\n\r\nimport {\r\n StyledAddWatchListSpan,\r\n StyledRemovedWatchListPlaceHolder,\r\n StyledUnwatchPlaceholderAlert\r\n} from './UnwatchPlaceholder.styled'\r\n\r\ninterface IProps {\r\n vehicleInfo: IVehicleInfo\r\n viewStyle?: VehicleDetailsView\r\n}\r\nexport const UnwatchPlaceholder = ({ vehicleInfo, viewStyle = VehicleDetailsView.List }: IProps) => {\r\n const isListView = useMemo(() => viewStyle === VehicleDetailsView.List, [viewStyle])\r\n const getLocalText = useGlobalStore((state) => state.getLocalText, shallow)\r\n const {\r\n vehicleWatchListState: { isSaving, saveWatchList }\r\n } = useContext(VehicleContext)\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n {vehicleInfo.Title}\r\n {getLocalText('REMOVED_FROM_WATCHLIST', 'removed from Watch List!')}\r\n \r\n \r\n
\r\n \r\n \r\n {isSaving ? (\r\n \r\n ) : (\r\n \r\n {getLocalText('ADD_TO_WATCHLIST', 'Add to watchlist')}\r\n \r\n )}\r\n \r\n
\r\n \r\n )\r\n}\r\n","import VehicleDetailImage from './VehicleDetailImage'\r\nimport { UnwatchPlaceholder } from 'modules/Watchlist/UnwatchPlaceholder'\r\nimport { Col, Row, Form } from 'react-bootstrap'\r\nimport { IVehicleData } from '../../types/vehicleTypes'\r\nimport { StyledCarfaxCol, StyledVehicleDetailsCard } from './VehicleDetails.styled'\r\nimport { useContext } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport { VehicleInformation } from './VehicleInformation'\r\nimport { StyledVehicleDetailsColumn } from 'modules/VehicleList'\r\nimport { CarfaxAdvantage } from './CarfaxAdvantage'\r\nimport { getVdpUrl } from 'utils/urlUtils'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { StockwaveData } from 'modules/Stockwave/StockwaveData'\r\n\r\nexport interface IVehicleDetailsProps {\r\n vehicleData: IVehicleData\r\n enableRemovedWatchlistPlaceholder: boolean\r\n onSelect?: (e: boolean) => void\r\n showCheckbox?: boolean\r\n isSelected?: boolean\r\n isShowRemoveBidButton?: boolean\r\n}\r\n\r\nexport const VehicleListLayout = ({\r\n vehicleData,\r\n enableRemovedWatchlistPlaceholder,\r\n onSelect,\r\n isSelected,\r\n showCheckbox\r\n}: IVehicleDetailsProps) => {\r\n const { vehicle: vehicleInfo } = vehicleData\r\n const {\r\n vehicleData: {\r\n vehicle: { WatchListID }\r\n }\r\n } = useContext(VehicleContext)\r\n\r\n if (!WatchListID && enableRemovedWatchlistPlaceholder) {\r\n return (\r\n \r\n \r\n \r\n )\r\n }\r\n const handleCheckboxClick = (e: any) => {\r\n const { checked } = e.target as HTMLInputElement\r\n onSelect?.(checked)\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n {showCheckbox && (\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n \r\n )\r\n}\r\n","import { zIndex } from 'common/constants'\r\nimport {\r\n BuyItNowButtonContainer,\r\n BuyItNowButtonGroup,\r\n StyledAuctionButton\r\n} from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { StyledVehicleBidBuyInformation } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { StyledRemovedWatchListPlaceHolder } from 'modules/Watchlist/UnwatchPlaceholder.styled'\r\nimport styled from 'styled-components'\r\nimport { StyledVehicleAction } from './VehicleActions'\r\nimport { StyledTitleSection, StyledVehicleDetailsCard } from './VehicleDetails.styled'\r\nimport { StyledVehicleNote } from './VehicleNote.styled'\r\n\r\nexport const StyledBidBuyInfoSection = styled.div`\r\n display: flex;\r\n justify-content: space-between;\r\n`\r\n\r\nexport const StyledVehicleDetailsGridCard = styled(StyledVehicleDetailsCard)`\r\n ${StyledVehicleBidBuyInformation} {\r\n flex: 1;\r\n\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: flex-end;\r\n }\r\n\r\n ${StyledAuctionButton} {\r\n width: 100%;\r\n margin: 1rem 0 0 0;\r\n }\r\n\r\n row-gap: 0.25rem;\r\n\r\n .vehicle-detail-image-section {\r\n max-width: initial;\r\n position: relative;\r\n\r\n .vehicle-select {\r\n z-index: ${zIndex.floatingControls};\r\n }\r\n }\r\n\r\n .auction-info {\r\n flex-grow: 2;\r\n }\r\n\r\n .vehicle-info {\r\n gap: initial;\r\n }\r\n\r\n .stockwave-light-bulb-container {\r\n margin-left: 4rem;\r\n }\r\n\r\n ${StyledVehicleNote} {\r\n .vehicle-note {\r\n max-width: 20rem;\r\n }\r\n }\r\n\r\n ${BuyItNowButtonContainer} {\r\n flex-direction: column;\r\n row-gap: 0.5rem;\r\n }\r\n\r\n ${StyledTitleSection} {\r\n flex-direction: column;\r\n align-items: flex-start;\r\n }\r\n\r\n ${BuyItNowButtonGroup} {\r\n width: 100%;\r\n }\r\n\r\n ${StyledRemovedWatchListPlaceHolder} {\r\n .alert {\r\n flex-direction: column;\r\n }\r\n }\r\n\r\n ${StyledVehicleAction} {\r\n justify-content: space-between;\r\n }\r\n\r\n ${StyledTitleSection} {\r\n padding: 0;\r\n }\r\n`\r\n","export default __webpack_public_path__ + \"static/media/bmw-logo-new.dbdc79d9.png\";","import styled from 'styled-components'\r\nimport { StyledVehicleDetailImage } from './VehicleDetailImage.style'\r\nimport { zIndex } from 'common/constants'\r\n\r\nexport const StyledVehicleDetailsGridCardImage = styled(StyledVehicleDetailImage)`\r\n img {\r\n max-width: inherit;\r\n max-height: 22rem;\r\n\r\n object-fit: cover;\r\n object-position: center;\r\n\r\n &.img-err {\r\n object-fit: contain;\r\n }\r\n }\r\n\r\n .pill {\r\n border-radius: 0.5rem 0.5rem;\r\n padding: 0 0.5rem;\r\n }\r\n\r\n .page-indicator {\r\n position: absolute;\r\n z-index: ${zIndex.floatingControls};\r\n right: 0;\r\n margin: 0.5rem;\r\n background: #808080;\r\n color: #f0f0f0;\r\n }\r\n\r\n .carousel {\r\n .carousel-item {\r\n span {\r\n width: 100%;\r\n }\r\n\r\n img,\r\n span {\r\n height: 100%;\r\n }\r\n }\r\n\r\n a[class^='carousel-control-'] {\r\n width: 8%;\r\n opacity: 1;\r\n\r\n &:hover {\r\n opacity: 0.5;\r\n }\r\n }\r\n }\r\n .img-load-err {\r\n cursor: default;\r\n }\r\n`\r\n","import 'react-lazy-load-image-component/src/effects/blur.css'\r\n\r\nimport { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport classNames from 'classnames'\r\nimport bmwNewLogo from 'images/bmw-logo-new.png'\r\nimport { useContext, useEffect, useMemo, useState } from 'react'\r\nimport { Carousel } from 'react-bootstrap'\r\nimport { LazyLoadImage } from 'react-lazy-load-image-component'\r\nimport { IVehicleImage } from 'types/vehicleTypes'\r\n\r\nimport { StyledVehicleDetailsGridCardImage } from './VehicleDetailsGridCardImage.styled'\r\nimport { SliderContext } from 'contexts/SliderContext'\r\n\r\ninterface IProps {\r\n images: IVehicleImage[]\r\n vehicleInstanceID: number\r\n isDSI?: boolean\r\n}\r\n\r\ninterface IImage extends IVehicleImage {\r\n CanLoad: boolean\r\n}\r\n\r\nexport const VehicleDetailsGridCardImage = ({ images, vehicleInstanceID, isDSI = false }: IProps) => {\r\n const { setDisplaySlider, setSliderData, selectedImageID, selectedVehicle, showCarousel } = useContext(SliderContext)\r\n const [canLoadImage, setCanLoadImage] = useState(true)\r\n const [activeIndex, setActiveIndex] = useState(0)\r\n const imgList = useMemo(\r\n () => images?.map((img) => ({ ...img, CanLoad: true, Description: isDSI ? '' : img.Description })),\r\n [images]\r\n )\r\n useEffect(() => {\r\n if (selectedImageID && showCarousel && selectedVehicle === vehicleInstanceID) {\r\n let imgIndex = imgList.findIndex((x) => x.ID === selectedImageID)\r\n setActiveIndex(imgIndex === -1 ? 0 : imgIndex)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [selectedImageID, imgList])\r\n\r\n const handleSelect = (selectedIndex: number) => {\r\n setActiveIndex(selectedIndex)\r\n\r\n setCanLoadImage(imgList[selectedIndex].CanLoad)\r\n }\r\n\r\n const handleBrokenImageURL = (id: number) => {\r\n imgList.find((img) => img.ID === id).CanLoad = false\r\n setCanLoadImage(false)\r\n }\r\n\r\n if (!imgList || imgList.length === 0) {\r\n return (\r\n \r\n {/* eslint-disable-next-line jsx-a11y/img-redundant-alt */}\r\n
\r\n \r\n )\r\n }\r\n\r\n return (\r\n \r\n {imgList?.length > 1 ? (\r\n <>\r\n {`${activeIndex + 1} / ${imgList.length}`}\r\n }\r\n prevIcon={}\r\n activeIndex={activeIndex}\r\n onSelect={handleSelect}\r\n >\r\n {imgList.map((img, idx) => (\r\n \r\n {\r\n currentTarget.onerror = null\r\n handleBrokenImageURL(img.ID)\r\n }}\r\n onClick={() => {\r\n if (canLoadImage) {\r\n setSliderData(imgList)\r\n setDisplaySlider(!!img.ImageURL, imgList[activeIndex].ID, vehicleInstanceID)\r\n }\r\n }}\r\n />\r\n \r\n ))}\r\n \r\n >\r\n ) : (\r\n {\r\n currentTarget.onerror = null\r\n handleBrokenImageURL(imgList[0].ID)\r\n }}\r\n onClick={() => {\r\n if (canLoadImage) {\r\n setSliderData(imgList)\r\n setDisplaySlider(!!imgList[0].ImageURL, imgList[0].ID, vehicleInstanceID)\r\n }\r\n }}\r\n />\r\n )}\r\n \r\n )\r\n}\r\n","import { VehicleDetailsView } from 'common/constants'\r\nimport { UnwatchPlaceholder } from 'modules/Watchlist/UnwatchPlaceholder'\r\nimport { useContext } from 'react'\r\nimport { Form } from 'react-bootstrap'\r\n\r\nimport { StyledBidBuyInfoSection, StyledVehicleDetailsGridCard } from './VehicleDetailsGridCard.styled'\r\nimport { VehicleDetailsGridCardImage } from './VehicleDetailsGridCardImage'\r\nimport { VehicleNote } from './VehicleNote'\r\nimport { StyledVehicleDetailsColumn } from 'modules/VehicleList'\r\nimport { VehicleTitleSection } from './VehicleTitleSection'\r\nimport { VehicleProperties } from './VehicleProperties'\r\nimport { VehicleActions } from './VehicleActions'\r\nimport { VehicleVin } from './VehicleDetails.styled'\r\nimport { IVehicleDetailsProps } from './VehicleDetails'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport { StyledVehicleBidBuyInformation } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { VehiclePriceSection } from './VehiclePriceSection'\r\nimport { VehicleTags } from './VehicleTags'\r\nimport { VehicleBidHistoryLink } from './VehicleBidHistoryLink'\r\nimport { VehicleTimer } from './VehicleTimer'\r\nimport { VehicleBidBuyActions } from './VehicleBidBuyActions'\r\nimport { UserMaxBid } from './UserMaxBid'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { StockwaveData } from 'modules/Stockwave/StockwaveData'\r\n\r\nexport const VehicleGridLayout = ({\r\n vehicleData,\r\n enableRemovedWatchlistPlaceholder,\r\n onSelect,\r\n isSelected,\r\n showCheckbox\r\n}: IVehicleDetailsProps) => {\r\n const { getSystemSetting } = useGlobalStore()\r\n const { vehicle: vehicleInfo } = vehicleData\r\n const {\r\n vehicleData: {\r\n vehicle: { WatchListID }\r\n }\r\n } = useContext(VehicleContext)\r\n\r\n const fieldLimit = (getSystemSetting('BGD_GRIDVIEW_VEHICLE_DETAILS_DISPLAY_FIELDS_LIMIT') as number) || null\r\n\r\n if (!WatchListID && enableRemovedWatchlistPlaceholder) {\r\n return (\r\n \r\n \r\n \r\n )\r\n }\r\n\r\n const handleCheckboxClick = (e: any) => {\r\n const { checked } = e.target as HTMLInputElement\r\n onSelect?.(checked)\r\n }\r\n return (\r\n \r\n \r\n \r\n
\r\n
\r\n {showCheckbox && (\r\n
\r\n )}\r\n\r\n
\r\n
\r\n \r\n \r\n {vehicleData.vehicle.VIN}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\nimport { extraLargeScreen, largeScreen, mediumScreen, smallScreen } from 'common/theme'\r\nimport { StyledHomeSectionHeaderBanner } from 'components/Header/HomeSectionHeader.styled'\r\nimport { StyledNoActivity } from 'modules/BuyerActivity/NoActivity.styled'\r\nimport { StyledRibbonContainer } from 'modules/DealerVehicleManagement/VehicleDetails.styled'\r\nimport { Row } from 'react-bootstrap'\r\nimport { StyledVehicleAction } from 'modules/DealerVehicleManagement/VehicleActions'\r\n\r\nexport const StyledVehicleList = styled.div`\r\n padding: 2.4rem;\r\n\r\n background-color: #f8f8f8;\r\n\r\n .grid-card-col {\r\n display: flex;\r\n }\r\n\r\n ${StyledNoActivity} {\r\n @media (min-width: ${mediumScreen}) {\r\n img {\r\n width: 21rem;\r\n height: 20rem;\r\n }\r\n }\r\n }\r\n`\r\nStyledVehicleList.displayName = 'StyledVehicleList'\r\n\r\nexport const StyledSelectAll = styled.div`\r\n margin: 0.5rem 1.5rem;\r\n`\r\n\r\nexport const StyledStickyHeaderPage = styled.div`\r\n ${StyledHomeSectionHeaderBanner} {\r\n white-space: nowrap;\r\n @media (max-width: ${smallScreen}) {\r\n .navigation-link {\r\n display: none;\r\n }\r\n }\r\n }\r\n`\r\nexport const StyledHeaderActions = styled.div`\r\n display: flex;\r\n align-items: center;\r\n gap: 2rem;\r\n font-size: 1.6rem;\r\n\r\n @media (max-width: ${extraLargeScreen}) {\r\n gap: 1rem;\r\n }\r\n\r\n margin-right: 2.5rem;\r\n\r\n .view-icons {\r\n gap: 1.2rem;\r\n .prism-icon-svg {\r\n opacity: 0.5;\r\n\r\n &.active,\r\n &:hover {\r\n opacity: 1;\r\n }\r\n }\r\n }\r\n\r\n .right-action,\r\n .prism-icon-svg {\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n\r\n .right-action:hover,\r\n .btn-current-sort:hover {\r\n opacity: 0.5;\r\n }\r\n\r\n .right-action,\r\n .view-icons {\r\n display: flex;\r\n align-items: center;\r\n cursor: pointer;\r\n }\r\n\r\n @media (max-width: ${smallScreen}) {\r\n .view-icons {\r\n display: none;\r\n }\r\n .export-view {\r\n display: none;\r\n }\r\n }\r\n\r\n .dropdown-toggle:after {\r\n display: none;\r\n }\r\n\r\n .chevron-down-icon {\r\n margin-top: 0.5rem;\r\n }\r\n\r\n .dropdown-item {\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-weight: 600;\r\n height: 2.5rem;\r\n display: flex;\r\n align-items: center;\r\n transition: all 167ms ease-in;\r\n position: relative;\r\n background-color: transparent;\r\n\r\n &:hover {\r\n color: white;\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n }\r\n }\r\n\r\n .dropdown-menu.show {\r\n transform: translate(30px, 26px) !important;\r\n }\r\n`\r\n\r\nexport const StyledVehicleDetailsColumn = styled.div`\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n height: 100%;\r\n`\r\n\r\nexport const StyledVehicleDetailsHeaderRow = styled(Row)`\r\n flex-wrap: unset;\r\n justify-content: space-between;\r\n @media (max-width: ${largeScreen}) {\r\n flex-wrap: wrap;\r\n ${StyledVehicleAction} {\r\n width: 100%;\r\n }\r\n ${StyledRibbonContainer} {\r\n width: 100%;\r\n }\r\n }\r\n`\r\nexport const StyledVehicleDetailsBody = styled.div``\r\n","import { IconSvg } from '@prism/icon'\r\nimport classNames from 'classnames'\r\nimport { DEFAULT_ERROR_MESSAGE, SessionStorageKey, VehicleDetailsView } from 'common/constants'\r\nimport { Loader, OverlayLoader } from 'components/Loader'\r\nimport { Paging } from 'components/Paging'\r\nimport ScrollButton from 'components/ScrollButton/ScrollButton'\r\nimport { Sort } from 'components/Sort/Sort'\r\nimport { useDealerManagedVehicles } from 'hooks/useDealerManagedVehicles'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport NoActivity from 'modules/BuyerActivity/NoActivity'\r\nimport { VehicleContextProvider } from 'modules/DealerVehicleManagement/VehicleContext'\r\nimport React, { ReactElement, ReactNode, useContext, useEffect, useMemo, useState } from 'react'\r\nimport { Col, ColProps, Form, Row } from 'react-bootstrap'\r\nimport { IBaseCollectionRequest, IBaseCollectionResponse, ISortBy } from 'types/baseTypes'\r\nimport { GetBidVehiclesRequest, IGetBidVehiclesResponse, IVehicleData } from 'types/vehicleTypes'\r\n\r\nimport { IVehicleDetailsProps, VehicleListLayout } from 'modules/DealerVehicleManagement/VehicleDetails'\r\nimport { VehicleGridLayout } from 'modules/DealerVehicleManagement/VehicleDetailsGridCard'\r\nimport { StyledHeaderActions, StyledSelectAll, StyledStickyHeaderPage, StyledVehicleList } from './VehicleList.styled'\r\nimport { VehicleListContext } from './VehicleListContext'\r\nimport { SliderContext } from 'contexts/SliderContext'\r\nimport { VehicleStickyBar } from './VehicleStickyBar'\r\n\r\ninterface IProps {\r\n title: ReactNode\r\n queryFunction: (request: IBaseCollectionRequest) => Promise>\r\n queryRequest?: IBaseCollectionRequest\r\n countQueryFunction?: (request: IBaseCollectionRequest) => Promise>\r\n navigationLink?: (count: number) => ReactElement\r\n checkboxAction?: (selectedVehicles: number[], vehicles?: IVehicleData[]) => ReactElement\r\n enableRemovedWatchlistPlaceholder?: boolean\r\n noActivityMessage: string\r\n showCheckbox?: boolean\r\n isShowRemoveBidButton?: boolean\r\n bottomPagination?: boolean\r\n gridLayoutColProps?: ColProps\r\n}\r\nexport const VehicleList = ({\r\n title,\r\n queryFunction,\r\n queryRequest,\r\n countQueryFunction,\r\n navigationLink,\r\n enableRemovedWatchlistPlaceholder = false,\r\n isShowRemoveBidButton = false,\r\n noActivityMessage,\r\n checkboxAction,\r\n showCheckbox,\r\n bottomPagination = true,\r\n gridLayoutColProps = { xs: 12, xl: 3, lg: 4, md: 6 }\r\n}: IProps) => {\r\n const { currentPage, currentPageSize, currentSortBy, selectedVehicles, setVehiclesState } =\r\n useContext(VehicleListContext)\r\n const { setDisplaySlider } = useContext(SliderContext)\r\n const {\r\n loading,\r\n sortOptions,\r\n vehicles,\r\n refetch,\r\n totalRecords: totalRecordsForHeader,\r\n TotalPages\r\n } = useDealerManagedVehicles(\r\n queryFunction,\r\n useMemo(() => {\r\n if (!queryRequest) return new GetBidVehiclesRequest(currentPageSize, currentPage, currentSortBy)\r\n\r\n return {\r\n ...queryRequest,\r\n ...new GetBidVehiclesRequest(currentPageSize, currentPage, currentSortBy)\r\n }\r\n }, [queryRequest, currentPageSize, currentPage, currentSortBy])\r\n )\r\n\r\n const { data: { TotalRecords: totalRecordsForNavlink } = {} as IGetBidVehiclesResponse, loading: countLoading } =\r\n useFetch(() =>\r\n countQueryFunction\r\n ? countQueryFunction(new GetBidVehiclesRequest(currentPageSize, currentPage, currentSortBy))\r\n : Promise.resolve({} as IBaseCollectionResponse)\r\n )\r\n const handleSortChange = (selectedSortBy: ISortBy) => {\r\n setVehiclesState((state) => {\r\n state.currentSortBy = selectedSortBy\r\n state.selectedVehicles = []\r\n })\r\n }\r\n\r\n useEffect(() => {\r\n setVehiclesState((state) => {\r\n state.totalPages = TotalPages\r\n })\r\n }, [TotalPages, setVehiclesState])\r\n\r\n const [viewStyle, setViewStyle] = useState(\r\n (sessionStorage.getItem(SessionStorageKey.VIEW_VEHICLE_LIST) as VehicleDetailsView) || VehicleDetailsView.List\r\n )\r\n useEffect(() => {\r\n sessionStorage.setItem(SessionStorageKey.VIEW_VEHICLE_LIST, viewStyle)\r\n }, [viewStyle, setViewStyle])\r\n\r\n const isSelectAll = vehicles?.every((item) =>\r\n selectedVehicles.find((selectedId) => selectedId === item.vehicle.InstanceID)\r\n )\r\n\r\n const handleSelectAll = () => {\r\n setVehiclesState((state) => {\r\n if (isSelectAll) {\r\n state.selectedVehicles = []\r\n } else {\r\n state.selectedVehicles = vehicles.map((item) => item.vehicle.InstanceID)\r\n }\r\n })\r\n }\r\n const handleSelectVehicle = (instanceID: number, checked: boolean) => {\r\n if (checked && selectedVehicles.indexOf(instanceID) < 0) {\r\n setVehiclesState((state) => {\r\n state.selectedVehicles = [...selectedVehicles, instanceID]\r\n })\r\n }\r\n\r\n if (!checked && selectedVehicles.indexOf(instanceID) >= 0) {\r\n setVehiclesState((state) => {\r\n state.selectedVehicles = selectedVehicles.filter((item) => item !== instanceID)\r\n })\r\n }\r\n }\r\n useEffect(() => {\r\n window.scrollTo({\r\n top: 0,\r\n behavior: 'smooth'\r\n })\r\n }, [viewStyle])\r\n\r\n let colProps: ColProps\r\n let Card: React.FunctionComponent\r\n if (viewStyle === VehicleDetailsView.List) {\r\n colProps = { xs: 12 }\r\n Card = VehicleListLayout\r\n } else {\r\n colProps = gridLayoutColProps\r\n Card = VehicleGridLayout\r\n }\r\n\r\n const handlePageSizeChanged = (pageSizeSelected: number) => {\r\n setVehiclesState((state) => {\r\n state.currentPage = 0\r\n state.currentPageSize = Number(pageSizeSelected)\r\n })\r\n }\r\n\r\n const paginationClicked = (pageSelected: number) => {\r\n if (pageSelected === currentPage + 1) return\r\n\r\n setVehiclesState((state) => {\r\n state.currentPage = pageSelected - 1\r\n })\r\n }\r\n useEffect(() => {\r\n if (vehicles?.length > 0) {\r\n var vehicleIDs = vehicles.map((item) => item.vehicle.InstanceID)\r\n sessionStorage.setItem(SessionStorageKey.VEHICLE_INSTANCES, JSON.stringify(vehicleIDs))\r\n } else {\r\n sessionStorage.removeItem(SessionStorageKey.VEHICLE_INSTANCES)\r\n }\r\n }, [vehicles])\r\n\r\n useEffect(() => {\r\n setDisplaySlider(false, null, null)\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [queryRequest, currentPageSize, currentPage, currentSortBy])\r\n\r\n return (\r\n <>\r\n {loading && }\r\n \r\n \r\n {showCheckbox && checkboxAction?.(selectedVehicles, vehicles)}\r\n {countLoading ? (\r\n \r\n ) : (\r\n navigationLink &&\r\n navigationLink(countQueryFunction ? totalRecordsForNavlink ?? 0 : totalRecordsForHeader ?? 0)\r\n )}\r\n {totalRecordsForHeader > 0 && sortOptions?.length > 0 && (\r\n \r\n )}\r\n \r\n setViewStyle(VehicleDetailsView.List)}\r\n />\r\n setViewStyle(VehicleDetailsView.Grid)}\r\n />\r\n \r\n \r\n }\r\n />\r\n\r\n {vehicles && (\r\n \r\n {vehicles?.length > 0 ? (\r\n <>\r\n {showCheckbox && !!checkboxAction && (\r\n \r\n \r\n \r\n )}\r\n \r\n {vehicles.map((item, index) => (\r\n \r\n \r\n handleSelectVehicle(item.vehicle.InstanceID, checked)}\r\n enableRemovedWatchlistPlaceholder={enableRemovedWatchlistPlaceholder}\r\n vehicleData={item}\r\n isSelected={selectedVehicles.indexOf(item.vehicle.InstanceID) >= 0}\r\n />\r\n \r\n \r\n ))}\r\n
\r\n {bottomPagination && (\r\n \r\n )}\r\n >\r\n ) : (\r\n \r\n )}\r\n \r\n )}\r\n \r\n \r\n >\r\n )\r\n}\r\n","import { DEFAULT_SMALL_PAGE_SIZE } from 'common/constants'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { useVehicles } from 'hooks/useVehicles'\r\nimport { IBaseCollectionRequest, IBaseCollectionResponse } from 'types/baseTypes'\r\nimport { GetBidVehiclesRequest, IVehicleData } from 'types/vehicleTypes'\r\n\r\nexport const useDealerManagedVehicles = <\r\n TRequest extends IBaseCollectionRequest,\r\n TResponse extends IBaseCollectionResponse\r\n>(\r\n queryFunction: (request: TRequest) => Promise,\r\n getBidVehicleRequest?: TRequest\r\n) => {\r\n const {\r\n data: {\r\n Items,\r\n TotalRecords: totalRecords,\r\n SortOptions: sortOptions,\r\n SortBy: sortBy,\r\n TotalPages,\r\n PageNumber\r\n } = {} as TResponse,\r\n loading,\r\n refetch\r\n } = useFetch(\r\n () => queryFunction(getBidVehicleRequest || (new GetBidVehiclesRequest(DEFAULT_SMALL_PAGE_SIZE) as TRequest)),\r\n [queryFunction, getBidVehicleRequest]\r\n )\r\n const { vehicles } = useVehicles(Items)\r\n\r\n return { refetch, loading, totalRecords, vehicles, sortOptions, sortBy, TotalPages, PageNumber }\r\n}\r\n","import { matchPath } from 'react-router'\r\n\r\nexport enum AppRoutes {\r\n // Login = '/login',\r\n Dashboard = '/dashboard',\r\n ContactUs = '/contactUs',\r\n Terms = '/terms',\r\n Forgot = '/forgot',\r\n Privacy = '/privacy',\r\n FAQs = '/faqs',\r\n WatchList = '/watchlist',\r\n ManageBids = '/managebids',\r\n VDP = '/vehicle/:vehicleInstanceId',\r\n SearchResult = '/search'\r\n}\r\n\r\nconst routes = Object.keys(AppRoutes).map((key) => {\r\n return {\r\n path: AppRoutes[key],\r\n name: key\r\n }\r\n})\r\n\r\nexport const REACT_ROUTES = routes\r\n\r\nexport const isReactRoutes = (pathname: string) => {\r\n if (pathname) {\r\n const [path] = pathname.split(/[?#]/)\r\n return REACT_ROUTES.some((item) =>\r\n matchPath(path, {\r\n exact: true,\r\n path: item.path\r\n })\r\n )\r\n }\r\n return false\r\n}\r\n","import { IUserClaimReponse } from 'types/userTypes'\r\n\r\nexport const addDefaultAttributes = (data: IUserClaimReponse) => {\r\n if (typeof newrelic === 'object') {\r\n newrelic.setCustomAttribute('userid', data.UserId?.toString())\r\n newrelic.setCustomAttribute('username', data.Username)\r\n newrelic.setCustomAttribute('buyercode', data.CurrentBuyerCode)\r\n newrelic.setCustomAttribute('buyername', data.DealershipName)\r\n }\r\n}\r\n","import { INewsModel } from './../types/rmsGlobalTypes'\r\nimport { rmsAuthModel } from 'common/rmsGlobal'\r\nimport { IRmsGlobal, IVendorInfo } from 'types/rmsGlobalTypes'\r\nimport { IUserClaimReponse } from 'types/userTypes'\r\nimport { addDefaultAttributes } from 'utils/newrelicUtilts'\r\nimport { parseJson } from 'utils/utils'\r\nimport create from 'zustand'\r\nimport { getUserClaims } from './../apis/userApis'\r\nimport { IAppSettings } from './../types/rmsAuthModel'\r\nimport { ISystemSetting } from '../types/baseTypes'\r\n\r\nexport interface IUserClaimState {\r\n isAuthenticated: boolean\r\n userClaims: IUserClaimReponse\r\n vendor: IVendorInfo\r\n appSettings: IAppSettings\r\n localText: Record\r\n rules: string[]\r\n systemSettings: Record\r\n featureToggles: Record\r\n errorMessages: Record\r\n newsModel: INewsModel\r\n serverTime: Date\r\n clientTime: Date\r\n\r\n fetchUserClaim: () => Promise\r\n getLocalText: (key: string, defaultText?: string) => string\r\n isInRule: (key: string) => boolean\r\n getSystemSetting: (key: string) => string | number | ISystemSetting\r\n getFeatureToggle: (key: string) => string | number | ISystemSetting\r\n clearError: () => void\r\n}\r\n\r\nexport const useGlobalStore = create((set, get) => ({\r\n isAuthenticated: rmsAuthModel?.isAuthenticated as boolean,\r\n userClaims: {} as IUserClaimReponse,\r\n vendor: rmsAuthModel?.vendor as IVendorInfo,\r\n appSettings: rmsAuthModel?.appSettings as IAppSettings,\r\n localText: rmsAuthModel?.localText as Record,\r\n rules: [] as string[],\r\n systemSettings: {} as Record,\r\n featureToggles: {} as Record,\r\n errorMessages: rmsAuthModel?.errorMessages as Record,\r\n newsModel: rmsAuthModel?.newsModel,\r\n // In the case when the server time is not fetched yet\r\n serverTime: new Date(),\r\n clientTime: new Date(),\r\n\r\n fetchUserClaim: async () => {\r\n const userClaim = await getUserClaims()\r\n if (userClaim) {\r\n const rmsGlobal = parseJson(userClaim.RmsGlobal) as IRmsGlobal\r\n addDefaultAttributes(userClaim)\r\n set((state) => ({\r\n ...state,\r\n userClaims: userClaim,\r\n localText: { ...state.localText, ...rmsGlobal.localText },\r\n rules: [...state.rules, ...rmsGlobal.rules, ...userClaim.Rules].map((rule) => rule.toLowerCase()),\r\n systemSettings: rmsGlobal.systemSettings,\r\n featureToggles: rmsGlobal.featureToggles,\r\n serverTime: new Date(userClaim.ServerUTCTime)\r\n }))\r\n }\r\n },\r\n getLocalText: (key, defaultText) => {\r\n const localText = get().localText\r\n if (localText && key) {\r\n return localText[key] || defaultText\r\n }\r\n return defaultText\r\n },\r\n isInRule: (key) => {\r\n const rules = get().rules as string[]\r\n if (rules) {\r\n return rules.includes(key.toLocaleLowerCase())\r\n }\r\n return false\r\n },\r\n getSystemSetting: (key) => {\r\n const systemSettings = get().systemSettings\r\n if (systemSettings) {\r\n return systemSettings[key] || ''\r\n }\r\n return ''\r\n },\r\n getFeatureToggle: (key) => {\r\n const featureToggles = get().featureToggles\r\n if (featureToggles) {\r\n return featureToggles[key] || ''\r\n }\r\n return ''\r\n },\r\n clearError: () => {\r\n set((state) => ({\r\n ...state,\r\n errorMessages: undefined\r\n }))\r\n }\r\n}))\r\n","import { CollapseProps, Collapse as BootstrapCollapse } from 'react-bootstrap'\r\n\r\nconst Collapse = ({ children, ...restProps }: CollapseProps) => {\r\n return (\r\n \r\n {children}
\r\n \r\n )\r\n}\r\n\r\nexport default Collapse\r\n","function CaretDownFill(props) {\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport default CaretDownFill\r\n","function CaretRightFill(props) {\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport default CaretRightFill\r\n","import { camelCase, startCase } from 'lodash'\r\nimport parse from 'html-react-parser'\r\nimport log from './logger'\r\n\r\nexport const parseNumberWithCommas = (inputText: string) => {\r\n return parseFloat(inputText.replace(/,/g, ''))\r\n}\r\nexport const capitalize = (title: string) => {\r\n return startCase(camelCase(title))\r\n}\r\nexport const parseHtml = (html: string) => {\r\n try {\r\n return parse(html)\r\n } catch (error) {\r\n log.error(error)\r\n }\r\n\r\n return null\r\n}\r\n\r\nexport const formatShortContext = (length: number, text: string) => {\r\n if (text) {\r\n var shortText = text.substring(0, length)\r\n return shortText\r\n }\r\n return ''\r\n}\r\n","import { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\ninterface IProps {\r\n carouselSize: number\r\n}\r\n\r\nexport const StyledSlideshowGallery = styled(Modal)`\r\n overflow-x: hidden !important;\r\n overflow-y: hidden !important;\r\n padding-left: 0 !important;\r\n\r\n .modal-dialog {\r\n max-width: unset;\r\n width: 100%;\r\n height: 100%;\r\n margin: 0;\r\n }\r\n\r\n .modal-content {\r\n height: 100%;\r\n border: 0;\r\n .modal-body {\r\n padding: 0;\r\n }\r\n .close-btn {\r\n position: absolute;\r\n right: 2rem;\r\n top: 0;\r\n z-index: 999999;\r\n background: #fff;\r\n border: 0;\r\n border-radius: 0 0 0.5rem 0.5rem;\r\n margin: 0;\r\n font-size: 2rem;\r\n font-weight: bold;\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n height: 5rem;\r\n width: 6rem;\r\n }\r\n }\r\n\r\n .modal-title.h4 {\r\n font-weight: 600;\r\n }\r\n\r\n .image-container {\r\n background-color: black;\r\n height: calc(100vh - 8rem);\r\n\r\n .transform-area,\r\n .react-transform-wrapper {\r\n width: 100%;\r\n height: 100%;\r\n .react-transform-component {\r\n position: absolute;\r\n }\r\n @media screen and (orientation: portrait) {\r\n img {\r\n max-width: 100vw;\r\n }\r\n }\r\n @media screen and (orientation: landscape) {\r\n img {\r\n height: calc(100vh - 8rem);\r\n width: auto;\r\n }\r\n }\r\n }\r\n\r\n .zoom-tools {\r\n position: absolute;\r\n top: 2rem;\r\n left: 2rem;\r\n .zoom-in-btn,\r\n .zoom-out-btn {\r\n font-size: 2rem;\r\n font-weight: bold;\r\n width: 4rem;\r\n z-index: 999999;\r\n border-radius: 0.5rem;\r\n background-color: transparent;\r\n opacity: 0.8;\r\n color: white;\r\n display: block;\r\n margin-bottom: 1rem;\r\n }\r\n\r\n .zoom-out-btn:hover,\r\n .zoom-in-btn:hover {\r\n cursor: pointer;\r\n opacity: 1;\r\n }\r\n }\r\n\r\n .previous-btn,\r\n .next-btn {\r\n position: absolute;\r\n width: 4rem;\r\n height: 4rem;\r\n text-align: center;\r\n padding: 0.5rem 0;\r\n border: 0.2rem solid white;\r\n border-radius: 0.5rem;\r\n opacity: 0.5;\r\n color: white;\r\n background-color: black;\r\n top: 40%;\r\n }\r\n\r\n .previous-btn {\r\n left: 2rem;\r\n }\r\n\r\n .next-btn {\r\n right: 2rem;\r\n }\r\n\r\n .previous-btn:hover,\r\n .next-btn:hover {\r\n opacity: 0.7;\r\n cursor: pointer;\r\n }\r\n }\r\n .img-description {\r\n position: absolute;\r\n opacity: 0.5;\r\n color: white;\r\n font-size: 1.6rem;\r\n background: black;\r\n bottom: 15%;\r\n left: 2rem;\r\n }\r\n .slider-container {\r\n background-color: white;\r\n height: 10rem;\r\n bottom: 0;\r\n text-align: center;\r\n svg {\r\n color: ${({ theme }) => theme.colors.primary};\r\n width: 100%;\r\n }\r\n\r\n img {\r\n height: 7rem;\r\n max-width: 9rem;\r\n object-fit: cover;\r\n padding: 0.5rem;\r\n border: 2px solid ${({ theme }) => theme.colors.inputBorder};\r\n &.selected {\r\n border: 2px solid ${({ theme }) => theme.colors.primary};\r\n }\r\n :hover {\r\n cursor: pointer;\r\n }\r\n }\r\n .carousel-control-prev,\r\n .carousel-control-next {\r\n width: 8%;\r\n opacity: 1;\r\n top: 1rem;\r\n }\r\n\r\n .carousel-control-prev:hover,\r\n .carousel-control-next:hover {\r\n opacity: 0.5;\r\n }\r\n .carousel-inner {\r\n margin: 0.5rem 10% 0 10%;\r\n width: auto;\r\n align-items: center;\r\n }\r\n .carousel-item {\r\n .col {\r\n width: calc(100% / ${({ carouselSize }) => carouselSize});\r\n flex-grow: unset;\r\n flex-basis: unset;\r\n }\r\n }\r\n }\r\n`\r\n","import { chunk } from 'lodash'\r\nimport { Fragment, useEffect, useState, useLayoutEffect, useContext } from 'react'\r\nimport { Carousel, Col, Modal, Row } from 'react-bootstrap'\r\nimport { IVehicleImage } from 'types/vehicleTypes'\r\nimport { LazyLoadImage } from 'react-lazy-load-image-component'\r\nimport 'react-lazy-load-image-component/src/effects/blur.css'\r\nimport { StyledSlideshowGallery } from './SlideShowGallery.styled'\r\nimport { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch'\r\nimport { faChevronRight, faChevronLeft } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport useWindowSize from 'hooks/useWindowSize'\r\nimport { BIG_SLIDER_ITEM_SIZE, fullScreenIcon, HUGE_SLIDER_ITEM_SIZE, MEDIUM_SLIDER_ITEM_SIZE } from 'common/constants'\r\nimport { SliderContext } from 'contexts/SliderContext'\r\nimport { extraExtraLargeScreenSize, mediumScreenSize } from 'common/theme'\r\n\r\ninterface ISlideshowGalleryProps {\r\n show: boolean\r\n onHide: any\r\n images: IVehicleImage[]\r\n defaultID: number\r\n showCarousel: boolean\r\n}\r\n\r\nexport const SlideshowGallery = ({ show, onHide, images, defaultID, showCarousel }: ISlideshowGalleryProps) => {\r\n const [selectedImageIndex, setSelectedImageIndex] = useState(0)\r\n const [pageActive, setPageActive] = useState(0)\r\n const [pageSize, setPageSize] = useState(BIG_SLIDER_ITEM_SIZE)\r\n const [pageItems, setPageItems] = useState(null)\r\n const { setCurrentImageID } = useContext(SliderContext)\r\n const { width } = useWindowSize()\r\n\r\n useLayoutEffect(() => {\r\n if (width <= mediumScreenSize) {\r\n setPageSize(MEDIUM_SLIDER_ITEM_SIZE)\r\n } else if (width <= extraExtraLargeScreenSize) {\r\n setPageSize(BIG_SLIDER_ITEM_SIZE)\r\n } else setPageSize(HUGE_SLIDER_ITEM_SIZE)\r\n setPageItems(chunk(images, pageSize))\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [images, pageSize, width])\r\n\r\n useEffect(() => {\r\n const imageIndex = images?.findIndex((x) => x.ID === defaultID)\r\n const pageItemsIndex = pageItems?.findIndex((x) => x.find((y) => y.ID === defaultID))\r\n setSelectedImageIndex(imageIndex === -1 ? 0 : imageIndex)\r\n setPageActive(pageItemsIndex === -1 ? 0 : pageItemsIndex)\r\n\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [defaultID, pageItems])\r\n\r\n const handleImageChange = (imageIndex: number) => {\r\n setSelectedImageIndex(pageActive * pageSize + imageIndex)\r\n setCurrentImageID(images[pageActive * pageSize + imageIndex]?.ID)\r\n }\r\n\r\n const handleActivePage = (selectedIndex: number) => {\r\n setPageActive(selectedIndex)\r\n }\r\n\r\n const handleGoNext = () => {\r\n if (selectedImageIndex + 1 >= images.length) {\r\n setSelectedImageIndex(0)\r\n setPageActive(0)\r\n } else {\r\n setSelectedImageIndex(selectedImageIndex + 1)\r\n const imageID = images[selectedImageIndex + 1].ID\r\n setPageActive(pageItems.findIndex((x) => x.find((y) => y.ID === imageID)))\r\n setCurrentImageID(imageID)\r\n }\r\n }\r\n\r\n const handleGoPrevious = () => {\r\n if (selectedImageIndex - 1 < 0) {\r\n setPageActive(pageItems.length - 1)\r\n setSelectedImageIndex(images.length - 1)\r\n setCurrentImageID(images[images.length - 1]?.ID)\r\n } else {\r\n setSelectedImageIndex(selectedImageIndex - 1)\r\n const imageID = images[selectedImageIndex - 1].ID\r\n setPageActive(pageItems.findIndex((x) => x.find((y) => y.ID === imageID)))\r\n setCurrentImageID(imageID)\r\n }\r\n }\r\n\r\n return (\r\n onHide()}\r\n backdrop=\"static\"\r\n carouselSize={pageSize}\r\n isShowCarousel={showCarousel}\r\n >\r\n \r\n \r\n \r\n
\r\n {({ zoomIn, zoomOut, resetTransform }) => (\r\n \r\n resetTransform(0)}>\r\n
\r\n
\r\n \r\n
\r\n \r\n

zoomIn()}\r\n />\r\n

zoomOut()}\r\n />\r\n
\r\n {\r\n handleGoPrevious()\r\n resetTransform(0)\r\n }}\r\n >\r\n \r\n \r\n {\r\n handleGoNext()\r\n resetTransform(0)\r\n }}\r\n >\r\n \r\n \r\n \r\n {images[selectedImageIndex]?.DamageImageDescription || images[selectedImageIndex]?.Description}\r\n \r\n \r\n )}\r\n \r\n
\r\n {images?.length > 0 && showCarousel && (\r\n \r\n }\r\n prevIcon={}\r\n >\r\n {pageItems.map((images, pageIndex) => (\r\n \r\n \r\n {images.map((item, imageIndex) => (\r\n \r\n {\r\n handleImageChange(imageIndex)\r\n }}\r\n title={item.DamageImageDescription || item.Description}\r\n />\r\n \r\n ))}\r\n
\r\n \r\n ))}\r\n \r\n
\r\n )}\r\n \r\n \r\n )\r\n}\r\n","import { SlideshowGallery } from 'modules/VDP/SlideShowGallery'\r\nimport React, { createContext, useState } from 'react'\r\nimport { IVehicleImage } from 'types/vehicleTypes'\r\nexport interface ISliderContext {\r\n setDisplaySlider: (isShow: boolean, imageID: number, vehicleInstance: number) => void\r\n setSliderData: (images: IVehicleImage[], isShowCarousel?: boolean) => void\r\n setCurrentImageID: (id: number) => void\r\n selectedImageID: number\r\n selectedVehicle: number\r\n showCarousel: boolean\r\n}\r\n\r\nexport const SliderContext = createContext({} as ISliderContext)\r\n\r\nexport const SliderContextProvider = ({ children }: React.PropsWithChildren<{}>) => {\r\n const [showSlider, setShowSlider] = useState(false)\r\n const [images, setImages] = useState(null)\r\n const [selectedImageID, setSelectedImageID] = useState()\r\n const [selectedVehicle, setSelectedVehicle] = useState()\r\n const [showCarousel, setShowCarousel] = useState(true)\r\n\r\n const setDisplaySlider = (isShow: boolean, imageID: number, vehicleInstance: number) => {\r\n setShowSlider(isShow)\r\n setSelectedImageID(imageID)\r\n setSelectedVehicle(vehicleInstance)\r\n }\r\n\r\n const setSliderData = (images: IVehicleImage[], isShowCarousel: boolean = true) => {\r\n setImages(images)\r\n setShowCarousel(isShowCarousel)\r\n }\r\n const setCurrentImageID = (id: number) => {\r\n setSelectedImageID(id)\r\n }\r\n\r\n return (\r\n \r\n {\r\n setShowSlider(false)\r\n setImages([])\r\n }}\r\n images={images}\r\n defaultID={selectedImageID}\r\n showCarousel={showCarousel}\r\n >\r\n {children}\r\n \r\n )\r\n}\r\n","import { SessionStorageKey } from 'common/constants'\r\nimport log from 'utils/logger'\r\nimport create from 'zustand'\r\n\r\nexport interface ISignalRState {\r\n connectionID?: string\r\n showConnectionAlert?: boolean\r\n setShowConnectionAlert: (show?: boolean) => void\r\n connect: () => void\r\n susbcribeEvents: () => void\r\n subscribe: (ids: number[]) => Promise\r\n}\r\n\r\nexport const useSignalRStore = create((set, get) => ({\r\n connect: async () => {\r\n try {\r\n await $.connection.hub.start().promise()\r\n\r\n // SignalR connection id might not be available at this point\r\n if ($.connection.hub.id) {\r\n set((state) => ({ ...state, connectionID: $.connection.hub.id }))\r\n }\r\n } catch (err) {\r\n console.error('SignalR: Could not connect to server')\r\n }\r\n },\r\n susbcribeEvents: async () => {\r\n $.connection.hub.starting(() => {\r\n log.info('SignalR: Connection starting')\r\n set((state) => ({ ...state, showConnectionAlert: false }))\r\n })\r\n\r\n $.connection.hub.connectionSlow(() => {\r\n log.info('SignalR: Slow connection detected')\r\n })\r\n\r\n $.connection.hub.stateChanged((state) => {\r\n const connectionStates = {\r\n 0: 'connecting',\r\n 1: 'connected',\r\n 2: 'reconnecting',\r\n 4: 'disconnected'\r\n }\r\n log.info(\r\n 'SignalR: Connection state changed from: ' +\r\n connectionStates[state.oldState] +\r\n ' to: ' +\r\n connectionStates[state.newState]\r\n )\r\n if (state.newState === 1) {\r\n sessionStorage.removeItem(SessionStorageKey.SIGNAL_R_CONNECTION_TRY_RECOUNT)\r\n set((state) => ({ ...state, showConnectionAlert: false }))\r\n\r\n // SignalR connection id is available at this point\r\n if ($.connection.hub.id) {\r\n set((state) => ({ ...state, connectionID: $.connection.hub.id }))\r\n }\r\n }\r\n })\r\n\r\n $.connection.hub.reconnected(() => {\r\n log.info('SignalR: Reconnected')\r\n set((state) => ({ ...state, showConnectionAlert: false }))\r\n })\r\n\r\n $.connection.hub.disconnected(() => {\r\n var signalRConnectionRetryCount = sessionStorage.getItem(SessionStorageKey.SIGNAL_R_CONNECTION_TRY_RECOUNT)\r\n if (signalRConnectionRetryCount == null) {\r\n signalRConnectionRetryCount = '0'\r\n }\r\n var retryCount = parseInt(signalRConnectionRetryCount)\r\n log.info('SignalR: Reconnecting retry count:' + retryCount)\r\n if (retryCount < 3) {\r\n retryCount++\r\n sessionStorage.setItem(SessionStorageKey.SIGNAL_R_CONNECTION_TRY_RECOUNT, retryCount.toString())\r\n get().connect()\r\n } else {\r\n set((state) => ({ ...state, showConnectionAlert: true }))\r\n }\r\n })\r\n },\r\n setShowConnectionAlert: (show?: boolean) => set((state) => ({ ...state, showConnectionAlert: show })),\r\n subscribe: async (ids: number[]) => {\r\n if (get().connectionID) {\r\n await $.connection.notificationHub.server.subscribe(ids).promise()\r\n }\r\n }\r\n}))\r\n","import create from 'zustand'\r\n\r\ninterface IBiddingSidePanel {\r\n isOpen: () => boolean\r\n biddingVehicleInstanceId?: number\r\n setBiddingVehicleInstanceId: (vehicleInstanceId: number) => void\r\n}\r\n\r\nexport const useBiddingSidePanel = create((set, get) => ({\r\n biddingVehicleInstanceId: null,\r\n setBiddingVehicleInstanceId(vehicle) {\r\n set((state) => ({\r\n ...state,\r\n biddingVehicleInstanceId: vehicle\r\n }))\r\n },\r\n isOpen: () => !!get().biddingVehicleInstanceId\r\n}))\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledWatchListLink = styled.a`\r\n .icon {\r\n margin-right: 0.4rem;\r\n }\r\n`\r\n","import { IconSvg } from '@prism/icon'\r\nimport { useContext } from 'react'\r\nimport { Spinner } from 'react-bootstrap'\r\nimport { StyledWatchListLink } from './WatchlistLink.styled'\r\nimport { VehicleContext } from 'modules/DealerVehicleManagement/VehicleContext'\r\n\r\nexport const WatchlistLink = () => {\r\n const {\r\n vehicleData: {\r\n vehicle: { WatchListID }\r\n },\r\n vehicleWatchListState: { saveWatchList, isSaving }\r\n } = useContext(VehicleContext)\r\n\r\n return (\r\n \r\n {isSaving ? (\r\n \r\n ) : (\r\n \r\n {!WatchListID || WatchListID <= 0 ? (\r\n \r\n \r\n Watch\r\n \r\n ) : (\r\n \r\n \r\n Unwatch\r\n \r\n )}\r\n
\r\n )}\r\n \r\n )\r\n}\r\n","import { PopupLink } from 'components/Share/PopupLink'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { faExternalLinkAlt, faPencilAlt } from '@fortawesome/free-solid-svg-icons'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { Rules } from 'common/rules'\r\nimport { isSystemSettingsEnabled, SystemSettingsCode } from 'common/systemSettingsCode'\r\nimport { Button } from 'react-bootstrap'\r\nimport { IVehicleData } from 'types/vehicleTypes'\r\nimport { WatchlistLink } from 'modules/Watchlist/WatchlistLink'\r\nimport { useContext, useEffect } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport styled from 'styled-components'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { parseUrlSearchParams } from 'utils/urlParams'\r\nimport { IVDPSearchParams } from 'types/ISearchParams'\r\n\r\nexport const StyledVehicleAction = styled.div``\r\ninterface IProps {\r\n vehicleData: IVehicleData\r\n}\r\n\r\nexport const VehicleActions = ({ vehicleData }: IProps) => {\r\n const {\r\n vehicleData: {\r\n vehicle: { VehicleNote }\r\n },\r\n setEditingNote,\r\n retailView\r\n } = useContext(VehicleContext)\r\n const isInRule = useGlobalStore((state) => state.isInRule)\r\n const showCarfax = isInRule(Rules.ENABLE_CARFAX)\r\n const location = useLocation()\r\n const hideBuyOptions = parseUrlSearchParams(location.search).history === 'true'\r\n const showTrue360 = isSystemSettingsEnabled(SystemSettingsCode.SHOW_TRUE_360) && !hideBuyOptions && !retailView\r\n\r\n const { userInteraction } = useDtmAnalytics()\r\n\r\n const handleAnalyticCarfax = () => {\r\n userInteraction(`${window.webData.pageName} : carfax`, [\r\n { auctionInfo: vehicleData.auctionInfo, VIN: vehicleData.vehicle.VIN }\r\n ])\r\n }\r\n\r\n const handleEditNote = () => {\r\n setEditingNote(true)\r\n userInteraction(`${window.webData.pageName} : ${!!VehicleNote ? 'Edit Note' : 'Add Note'}`, [\r\n { auctionInfo: vehicleData.auctionInfo, VIN: vehicleData.vehicle.VIN }\r\n ])\r\n }\r\n\r\n return (\r\n \r\n {showTrue360 && (\r\n \r\n )}\r\n\r\n {showCarfax && (\r\n \r\n CARFAX \r\n \r\n \r\n )}\r\n \r\n {!hideBuyOptions && }\r\n \r\n )\r\n}\r\n","import { rmsAuthModel } from './rmsGlobal'\r\n\r\nexport const SystemSettingsCode = {\r\n ENABLE_DTM_ANALYTICS_TRACE: 'ENABLE_DTM_ANALYTICS_TRACE',\r\n DTM_ANALYTICS_ENVIRONMENT: 'DTM_ANALYTICS_ENVIRONMENT',\r\n SHOW_TRUE_360: 'SHOW_TRUE_FRAME_ICON'\r\n}\r\n\r\nexport const isSystemSettingsEnabled = (code: string) => {\r\n return rmsAuthModel?.systemSettings[code] === '1'\r\n}\r\n\r\nexport const getSystemSetting = (code: string) => {\r\n return rmsAuthModel?.systemSettings[code]\r\n}\r\n","import { zIndex } from 'common/constants'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\nimport { StyledSubMenu } from './SubMenu.styled'\r\n\r\nexport const StyledMainNav = styled.div<{ show?: boolean; isSticky?: boolean; assetFolder?: string }>`\r\n display: flex;\r\n justify-content: center;\r\n font-size: 1.6rem;\r\n z-index: ${zIndex.menu};\r\n\r\n .nav-item:hover ${StyledSubMenu} {\r\n opacity: 1;\r\n transform: translateY(0);\r\n pointer-events: initial;\r\n }\r\n\r\n .nav-link {\r\n margin: 0 1.5rem;\r\n font-weight: 600;\r\n color: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.text\r\n }\r\n return theme.headerNotSticky.text\r\n }};\r\n\r\n svg {\r\n fill: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.text\r\n }\r\n return theme.headerNotSticky.text\r\n }};\r\n }\r\n\r\n .active {\r\n color: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.textHover\r\n }\r\n return theme.headerNotSticky.textHover\r\n }};\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n }\r\n\r\n &:hover {\r\n color: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.textHover\r\n }\r\n return theme.headerNotSticky.textHover\r\n }};\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n color: ${({ theme }) => theme.colors.defaultTextColor}!important;\r\n }\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.xl}) {\r\n ul {\r\n .nav-item {\r\n > .nav-link {\r\n padding: 0.8rem 0;\r\n }\r\n }\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n background-color: ${({ theme }) => theme.colors.mobileMenuBackground};\r\n position: fixed;\r\n transform: ${({ show }) => (!!show ? 'translateX(0)' : 'translateX(100%)')};\r\n display: block;\r\n top: 0;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n z-index: ${zIndex.navbarMobile};\r\n min-width: 30rem;\r\n box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.15);\r\n transition: all 167ms ease-in;\r\n overflow-y: auto;\r\n ul {\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n .nav-item + .nav-item {\r\n border-top: 0.1rem solid ${({ theme }) => theme.colors.inputBorder};\r\n }\r\n .nav-item {\r\n width: 100%;\r\n border-top: 0.1rem solid ${({ theme }) => theme.colors.inputBorder};\r\n border-bottom: 0.1rem ${({ theme }) => theme.colors.defaultTextColor};\r\n\r\n &:hover > .nav-link {\r\n background-color: white;\r\n }\r\n\r\n > .nav-link {\r\n font-size: 1.8rem;\r\n height: 4rem;\r\n margin: unset;\r\n text-align: center;\r\n color: ${({ theme }) => theme.colors.primary};\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n }\r\n &.active {\r\n background: #d4d4d4;\r\n :after {\r\n content: none;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyledUnderlineSpan = styled.span<{ isSticky?: boolean; assetFolder?: string }>`\r\n position: relative;\r\n text-transform: uppercase;\r\n font-size: 1.5rem;\r\n\r\n &.active,\r\n &:hover {\r\n &:after {\r\n content: '';\r\n display: block;\r\n position: absolute;\r\n left: 50%;\r\n bottom: -0.5rem;\r\n width: 80%;\r\n height: 0.4rem;\r\n background: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.spanUnderline\r\n }\r\n return theme.headerNotSticky.spanUnderline\r\n }};\r\n border-radius: 2.5rem;\r\n\r\n transform: translateX(-50%);\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n &.active,\r\n &:hover {\r\n &:after {\r\n background: ${({ theme }) => theme.colors.primary};\r\n }\r\n }\r\n }\r\n`\r\nexport const StyledNavBar = styled.div<{ show?: boolean }>`\r\n display: flex;\r\n flex-direction: column;\r\n position: relative;\r\n /* flex-grow: 1; */\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: ${({ show }) => (!!show ? 'flex' : 'none')};\r\n }\r\n`\r\nexport const StyledCloseMenuButton = styled.a`\r\n display: none;\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: flex;\r\n font-size: 2.4rem;\r\n text-transform: uppercase;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n width: 3rem;\r\n height: 3rem;\r\n align-items: center;\r\n justify-content: center;\r\n margin: 0.3rem;\r\n cursor: pointer;\r\n font-weight: 600;\r\n transition: all 167ms ease-in;\r\n\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n }\r\n }\r\n`\r\nexport const StyledSubNav = styled.div`\r\n display: flex;\r\n flex-direction: column;\r\n padding: 0 1.5rem;\r\n\r\n ul {\r\n display: none;\r\n flex-direction: row;\r\n flex-wrap: wrap;\r\n list-style: none;\r\n gap: 1.2rem;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n .nav-link {\r\n font-size: 1.4rem;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n }\r\n\r\n &.active {\r\n display: flex;\r\n }\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n display: none;\r\n }\r\n`\r\n","import { ISRPSearchParams } from 'contexts/FilterSearchContext'\r\nimport produce from 'immer'\r\nimport { createContext, PropsWithChildren, useMemo, useState } from 'react'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { ISortBy } from 'types/baseTypes'\r\nimport { getDefaultSRPFilter, resetSRPFilter } from 'utils/menuUtils'\r\nimport { parseUrlSearchParams } from 'utils/urlParams'\r\n\r\nexport interface IVehicleListState {\r\n currentPage: number\r\n totalPages?: number\r\n currentSortBy: ISortBy\r\n currentPageSize: number\r\n selectedVehicles: number[]\r\n}\r\n\r\ntype SetStateAction = (state: T) => void\r\n\r\nexport interface IVehicleListContext extends IVehicleListState {\r\n setVehiclesState: (action: SetStateAction) => void\r\n}\r\n\r\nexport const VehicleListContext = createContext(null)\r\n\r\nexport const VehicleListContextProvider = ({ children }: PropsWithChildren) => {\r\n const location = useLocation()\r\n\r\n useMemo(() => {\r\n const query = parseUrlSearchParams(location.search)\r\n if (query?.clearSearch) {\r\n resetSRPFilter()\r\n }\r\n }, [location.search])\r\n\r\n const [state, setState] = useState({\r\n ...getDefaultSRPFilter(),\r\n selectedVehicles: []\r\n })\r\n\r\n const setVehiclesState = (action: SetStateAction) => {\r\n setState(produce(state, action))\r\n }\r\n return {children}\r\n}\r\n","import { StyledRibbon } from './Ribbon.styled'\r\nimport { useTheme } from 'styled-components'\r\nimport { useMemo } from 'react'\r\nimport classNames from 'classnames'\r\n\r\ninterface IProps {\r\n label: string\r\n backgroundColor?: string\r\n textColor?: string\r\n className?: string\r\n variant?: 'info' | 'success' | 'warning' | 'danger' | 'custom'\r\n title?: string\r\n onClick?: () => void\r\n}\r\n\r\nexport const Ribbon = ({ label, className, variant, backgroundColor, textColor, title, onClick }: IProps) => {\r\n const theme = useTheme()\r\n const bgColor = useMemo(\r\n () =>\r\n variant === 'info'\r\n ? theme.colors.ribbonInfoBackgroundColor\r\n : variant === 'success'\r\n ? theme.colors.ribbonSuccessBackgroundColor\r\n : variant === 'warning'\r\n ? theme.colors.ribbonWarningBackgroundColor\r\n : variant === 'danger'\r\n ? theme.colors.ribbonDangerBackgroundColor\r\n : backgroundColor,\r\n [\r\n variant,\r\n theme.colors.ribbonInfoBackgroundColor,\r\n theme.colors.ribbonSuccessBackgroundColor,\r\n theme.colors.ribbonWarningBackgroundColor,\r\n theme.colors.ribbonDangerBackgroundColor,\r\n backgroundColor\r\n ]\r\n )\r\n const txtColor = useMemo(\r\n () =>\r\n variant === 'info'\r\n ? theme.colors.infoColor\r\n : variant === 'success'\r\n ? theme.colors.successColor\r\n : variant === 'warning'\r\n ? theme.colors.warningColor\r\n : variant === 'danger'\r\n ? theme.colors.dangerColor\r\n : textColor,\r\n [\r\n variant,\r\n theme.colors.infoColor,\r\n theme.colors.successColor,\r\n theme.colors.warningColor,\r\n theme.colors.dangerColor,\r\n textColor\r\n ]\r\n )\r\n\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n","import { IVehicleData } from 'types/vehicleTypes'\r\ninterface IProps {\r\n vehicleData: IVehicleData\r\n}\r\n\r\nexport const StockwaveData = ({ vehicleData }: IProps) => {\r\n const stockwaveData = {\r\n Vin: vehicleData?.vehicle?.VIN,\r\n Year: vehicleData?.vehicle?.ModelYear,\r\n Make: vehicleData?.vehicle?.Make,\r\n Model: vehicleData?.vehicle?.Model,\r\n Subseries: vehicleData?.vehicle?.Derivative,\r\n Tranmission: vehicleData?.vehicle?.Transmission,\r\n Seller: vehicleData?.vehicle?.SaleChannelName,\r\n Mileage: vehicleData?.vehicle?.Mileage,\r\n Description: vehicleData?.vehicle?.Title,\r\n Trim: vehicleData?.vehicle?.Derivative,\r\n Color: vehicleData?.vehicle?.ExteriorColour,\r\n Interior_Color: vehicleData?.vehicle?.InteriorTrim,\r\n Facilitation_Location: vehicleData?.vehicle?.VehicleLocationCity,\r\n BodyStyle: vehicleData?.vehicle?.BodyStyle,\r\n Odometer: vehicleData?.vehicle?.Mileage,\r\n Source: vehicleData?.vehicle?.SourceCode,\r\n CRURL: `https://${window.location.hostname}/vehicle/${vehicleData?.vehicle?.InstanceID}`,\r\n VDPURL: `https://${window.location.hostname}/vehicle/${vehicleData?.vehicle?.InstanceID}`,\r\n Displacement: vehicleData?.vehicle?.EngineSize,\r\n CRSCORE: vehicleData?.vehicle?.Condition,\r\n PickupZip: vehicleData?.vehicle?.LocationPostCode,\r\n PickupAddress: `${vehicleData?.vehicle?.LocationAddressDetails}, ${vehicleData?.vehicle?.LocationPostCode}`,\r\n Engine: vehicleData?.vehicle.EngineDescription\r\n }\r\n\r\n return (\r\n \r\n {JSON.stringify(stockwaveData)}\r\n
\r\n )\r\n}\r\n","import shallow from 'zustand/shallow'\r\nimport { useEffect, useMemo } from 'react'\r\nimport { selectVehiclesByIds } from 'store/selectors'\r\nimport { useSignalRStore } from 'store/useSignalRStore'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { IVehicleData } from 'types/vehicleTypes'\r\n\r\nexport const useVehicles = (originalData: IVehicleData[]) => {\r\n const subscribe = useSignalRStore((state) => state.subscribe)\r\n const [vehiclesFromStore, addVehicles] = useVehicleStore((state) => [state.vehicles, state.addVehicles], shallow)\r\n\r\n const returnedVehicles = useMemo(\r\n () =>\r\n selectVehiclesByIds(\r\n originalData?.map((item) => item.vehicle.InstanceID),\r\n vehiclesFromStore\r\n ),\r\n [originalData, vehiclesFromStore]\r\n )\r\n useEffect(() => {\r\n if (!originalData?.length) {\r\n return\r\n }\r\n\r\n addVehicles(originalData)\r\n }, [addVehicles, originalData])\r\n\r\n useEffect(() => {\r\n if (!originalData?.length) {\r\n return\r\n }\r\n\r\n const instanceIds = originalData.map((item) => item.vehicle.InstanceID)\r\n subscribe(instanceIds)\r\n }, [originalData, subscribe])\r\n\r\n return { vehicles: returnedVehicles }\r\n}\r\n","import { IVehicleData } from 'types/vehicleTypes'\r\n\r\nexport const selectVehiclesByIds = (ids: number[], vehicles: IVehicleData[]) => {\r\n if (!ids) {\r\n return null\r\n }\r\n\r\n return vehicles.filter((item) => ids?.indexOf(item.vehicle.InstanceID) >= 0)\r\n}\r\n","import { VehicleStatuses } from 'common/constants'\r\nimport {\r\n StyledAuctionPrice,\r\n StyledAuctionText,\r\n StyledNoAvailable,\r\n StyledTag\r\n} from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { useContext } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\nexport const VehiclePriceSection = () => {\r\n const {\r\n vehicleData: { vehicle: vehicleInfo, auctionInfo, IsAvailable }\r\n } = useContext(VehicleContext)\r\n\r\n return (\r\n <>\r\n {IsAvailable ? (\r\n <>\r\n {vehicleInfo.StatusID === VehicleStatuses.SoldNotFunded && (\r\n <>\r\n \r\n {vehicleInfo.BuyItNowPrice !== 0 && vehicleInfo.BuyItNowPriceString}\r\n \r\n \r\n SOLD\r\n \r\n >\r\n )}\r\n\r\n {vehicleInfo.StatusID !== VehicleStatuses.SoldNotFunded && vehicleInfo.StatusID !== VehicleStatuses.OnSale && (\r\n \r\n {vehicleInfo.StatusDescription}\r\n \r\n )}\r\n\r\n {vehicleInfo.StatusID === VehicleStatuses.OnSale && (\r\n \r\n {auctionInfo && (\r\n <>\r\n {auctionInfo.CurrentPriceString}\r\n {auctionInfo.CanBuy &&\r\n vehicleInfo.BuyItNowPrice > auctionInfo.CurrentPrice &&\r\n !auctionInfo.IsDirectSale ? (\r\n \r\n Buy It Now Price:\r\n {vehicleInfo.BuyItNowPriceString}\r\n \r\n ) : (\r\n \r\n )}\r\n >\r\n )}\r\n {!auctionInfo && {vehicleInfo.FinalPriceString}}\r\n
\r\n )}\r\n >\r\n ) : (\r\n \r\n NO LONGER AVAILABLE\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { VehicleStatuses } from 'common/constants'\r\nimport { colorDanger, colorWinning } from 'common/theme'\r\nimport { StyledTag } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { useContext } from 'react'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport styled from 'styled-components'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport classNames from 'classnames'\r\n\r\nexport const StyledVehicleTags = styled.div`\r\n ${StyledTag} {\r\n width: 10rem;\r\n }\r\n`\r\n\r\ninterface IProps {\r\n direction?: 'left' | 'right'\r\n className?: string\r\n}\r\n\r\nexport const VehicleTags = ({ className, direction = 'left' }: IProps) => {\r\n const {\r\n vehicleData: { vehicle: vehicleInfo, auctionInfo }\r\n } = useContext(VehicleContext)\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n\r\n return (\r\n \r\n {vehicleInfo.StatusID === VehicleStatuses.OnSale && auctionInfo && auctionInfo.HasPreviousBid ? (\r\n \r\n \r\n \r\n {auctionInfo.IsHighestBidder ? getLocalText('WINNING', 'winning') : getLocalText('OUTBID', 'outbid')}\r\n \r\n \r\n
\r\n ) : (\r\n \r\n )}\r\n {vehicleInfo.StatusID !== VehicleStatuses.SoldNotFunded && Boolean(vehicleInfo.WatchListID) && (\r\n \r\n \r\n watching\r\n \r\n
\r\n )}\r\n \r\n )\r\n}\r\n","import { CountDownWithColor } from 'modules/BuyerActivity/CountDownWithColor'\r\nimport { useContext } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\nexport const VehicleTimer = () => {\r\n const {\r\n vehicleData: { vehicle: vehicleInfo, auctionInfo }\r\n } = useContext(VehicleContext)\r\n\r\n return \r\n}\r\n","import { Popover } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledPopOverPagination = styled(Popover)`\r\n label {\r\n font-weight: 600;\r\n margin-right: 1rem;\r\n }\r\n\r\n width: 300px;\r\n display: flex;\r\n padding: 1rem;\r\n justify-content: space-between;\r\n align-items: center;\r\n\r\n input {\r\n width: 8rem;\r\n margin-right: 1rem;\r\n }\r\n\r\n button {\r\n padding: 0 1rem;\r\n }\r\n`\r\n\r\nexport const StyledPagination = styled.div`\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n\r\n @media (max-width: 650px) {\r\n flex-direction: column;\r\n align-items: flex-start;\r\n row-gap: 1rem;\r\n }\r\n .pagination > div > li > a,\r\n .pagination > li > a,\r\n .pagination > li > span {\r\n border: none;\r\n border-radius: 0.3rem;\r\n }\r\n\r\n .page-link {\r\n position: relative;\r\n display: block;\r\n padding: 0.5rem 0.75rem;\r\n margin-left: -1px;\r\n line-height: 1.25;\r\n color: ${({ theme }) => theme.colors.primary};\r\n background-color: transparent;\r\n }\r\n .page-link:hover {\r\n z-index: 2;\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n text-decoration: none;\r\n background-color: ${({ theme }) => theme.colors.secondary};\r\n }\r\n\r\n .page-item.active .page-link {\r\n z-index: 3;\r\n color: ${({ theme }) => theme.colors.inputBackgroundColor};\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n }\r\n\r\n .record-per-page {\r\n display: flex;\r\n align-items: center;\r\n gap: 1rem;\r\n\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n }\r\n`\r\n","import { useRef, useState } from 'react'\r\nimport { FormControl as Input, Button, Overlay, Pagination } from 'react-bootstrap'\r\n\r\nimport { StyledPopOverPagination } from './Paging.styled'\r\n\r\ninterface IOverlayProps {\r\n totalPages: number\r\n onChangedPageValue: (pageSizeSelected: number) => void\r\n toPage: number\r\n handleChangedPage: (pageNum: number) => void\r\n}\r\n\r\nexport const OverlayEllipsis = ({ handleChangedPage, onChangedPageValue, toPage, totalPages }: IOverlayProps) => {\r\n const [showGotoPage, setShowGotoPage] = useState(false)\r\n\r\n const paginationRef = useRef(null)\r\n\r\n const onChangePage = () => {\r\n handleChangedPage(toPage)\r\n setShowGotoPage(false)\r\n }\r\n\r\n return (\r\n <>\r\n setShowGotoPage(false)}\r\n show={showGotoPage}\r\n placement=\"top-end\"\r\n transition={false}\r\n >\r\n \r\n \r\n \r\n
setShowGotoPage(true)} />\r\n \r\n >\r\n )\r\n}\r\n","import { PageSizeOptions, PAGINATION_ITEM_SIZE } from 'common/constants'\r\nimport { DropdownList } from 'layouts/DropdownList'\r\nimport { useState } from 'react'\r\nimport { Pagination, PaginationProps } from 'react-bootstrap'\r\nimport { generatePageItems } from 'utils/pagingUtils'\r\nimport { StyledPagination } from './Paging.styled'\r\nimport { OverlayEllipsis } from './OverlayEllipsis'\r\n\r\ninterface IProps extends PaginationProps {\r\n currentPageSize?: number\r\n totalPages: number\r\n currentPage: number\r\n showRecordsPerPage?: boolean\r\n handlePageSizeChanged?: (pageSizeSelected: number) => void\r\n handleChangedPage?: (pageNum: number) => void\r\n}\r\n\r\nexport const Paging = ({\r\n currentPageSize,\r\n handlePageSizeChanged,\r\n totalPages,\r\n currentPage,\r\n showRecordsPerPage = true,\r\n handleChangedPage,\r\n ...props\r\n}: IProps) => {\r\n const [goToPageValue, setGoToPageValue] = useState(currentPage + 1)\r\n\r\n const onChangedPageValue = (pageNum: number) => {\r\n if (pageNum > totalPages) setGoToPageValue(totalPages)\r\n else if (pageNum < 1) setGoToPageValue(1)\r\n else setGoToPageValue(pageNum)\r\n }\r\n\r\n const pageCount = generatePageItems(totalPages, currentPage + 1, PAGINATION_ITEM_SIZE).map((item) =>\r\n typeof item === 'number' ? (\r\n {\r\n handleChangedPage?.(item + 1)\r\n }}\r\n >\r\n {item + 1}\r\n \r\n ) : (\r\n \r\n )\r\n )\r\n\r\n return (\r\n \r\n {showRecordsPerPage && (\r\n \r\n Records per page:\r\n ({ id: size.toString(), value: size.toString() }))}\r\n onChange={handlePageSizeChanged}\r\n />\r\n
\r\n )}\r\n \r\n {pageCount}\r\n \r\n \r\n )\r\n}\r\n\r\nexport * from './Paging.styled'\r\n","export const generatePageItems = (totalPages: number, currentPage: number, numberOfDisplayItems: number) => {\r\n const items: (string | number)[] = new Array(numberOfDisplayItems)\r\n if (totalPages < numberOfDisplayItems) {\r\n for (let i = 0; i < totalPages; i++) {\r\n items[i] = i\r\n }\r\n return items\r\n }\r\n // get the temp position of current page\r\n const left = Math.max(\r\n 0,\r\n Math.min(totalPages - numberOfDisplayItems, currentPage - Math.floor(numberOfDisplayItems / 2))\r\n )\r\n\r\n for (let i = 0; i < numberOfDisplayItems; i += 1) {\r\n // set position in the paging items line base on numberOfDisplayItems\r\n items[i] = i + left\r\n }\r\n\r\n // replace non-ending items with placeholders\r\n if (items[0] > 0) {\r\n items[0] = 0\r\n items[1] = 'prev-ellipsis'\r\n }\r\n\r\n if (items[items.length - 1] < totalPages - 1) {\r\n items[items.length - 1] = totalPages - 1\r\n items[items.length - 2] = 'next-ellipsis'\r\n }\r\n return items\r\n}\r\n","import { colorDanger, gridBreakPoints, textColor, textTableHeaderColor } from 'common/theme'\r\nimport { Modal, Table } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyleBidsHistory = styled(Modal)`\r\n margin: 2rem 0;\r\n`\r\n\r\nexport const StyledModalContent = styled(Modal.Body)`\r\n width: 100%;\r\n height: 100%;\r\n padding-left: 1rem;\r\n padding-right: 1rem;\r\n h5 {\r\n padding: 0.5rem 0 0 1rem;\r\n }\r\n button {\r\n float: right;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n background-color: transparent;\r\n border-color: transparent;\r\n }\r\n`\r\n\r\nexport const StyleModalHeader = styled(Modal.Header)`\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n color: white;\r\n font-size: 1.8rem;\r\n text-transform: uppercase;\r\n .close span {\r\n font-size: 2rem;\r\n font-weight: normal;\r\n color: white;\r\n }\r\n`\r\n\r\nexport const StyledLabel = styled.span`\r\n font-weight: 600;\r\n text-transform: uppercase;\r\n`\r\n\r\nexport const StyledBidsHistoryTable = styled(Table)`\r\n tbody {\r\n position: relative;\r\n tr:hover {\r\n background-color: transparent;\r\n }\r\n }\r\n th {\r\n background-color: ${({ theme }) => theme.colors.modalHeader};\r\n color: ${textTableHeaderColor};\r\n font-size: 1.6rem;\r\n font-weight: 400;\r\n padding: 1rem;\r\n text-align: left !important;\r\n text-transform: uppercase;\r\n }\r\n th:last-child {\r\n width: 18rem;\r\n }\r\n tr {\r\n &:nth-child(odd) {\r\n background-color: #f2f2f2;\r\n :hover {\r\n background-color: #f2f2f2;\r\n }\r\n }\r\n &.highest-row {\r\n font-weight: bold;\r\n }\r\n }\r\n td {\r\n font-size: 1.2rem;\r\n color: ${textColor};\r\n padding: 1rem;\r\n border-top: 0;\r\n }\r\n th {\r\n text-align: center;\r\n }\r\n\r\n .type-of-bid {\r\n position: relative;\r\n min-width: 19rem;\r\n .winning-bid-icon {\r\n height: 4rem;\r\n position: absolute;\r\n right: -1.4rem;\r\n top: 0;\r\n }\r\n }\r\n .proxy-bid {\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-weight: 900;\r\n }\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n .type-of-bid {\r\n position: unset;\r\n .winning-bid-icon {\r\n position: relative;\r\n left: 2.1rem;\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyleBidsHistoryNoteSpan = styled.div`\r\n display: flex;\r\n flex-direction: column;\r\n align-items: flex-end;\r\n font-size: 1.2rem;\r\n color: ${colorDanger};\r\n font-weight: 700;\r\n`\r\n","import { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IAuctionInfo } from 'types/auctionTypes'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport shallow from 'zustand/shallow'\r\nimport winningBid from '../../images/winning-bid.png'\r\nimport {\r\n StyleBidsHistory,\r\n StyleBidsHistoryNoteSpan,\r\n StyledBidsHistoryTable,\r\n StyledLabel,\r\n StyledModalContent,\r\n StyleModalHeader\r\n} from './BidsHistoryModal.styled'\r\n\r\nimport { DateTime } from 'luxon'\r\nimport { ComponentProps } from 'react'\r\nimport { Modal } from 'react-bootstrap'\r\n\r\ninterface IBidsHistoryProps extends ComponentProps {\r\n auctionInfo: IAuctionInfo\r\n vehicleInfo: IVehicleInfo\r\n}\r\n\r\nexport const BidsHistoryModal = ({ auctionInfo, vehicleInfo, ...props }: IBidsHistoryProps) => {\r\n const getLocalText = useGlobalStore((state) => state.getLocalText, shallow)\r\n\r\n const vehicleVin = vehicleInfo.VIN\r\n const vehicleTitle = vehicleInfo.Title\r\n const bidHistories = auctionInfo.BidHistory\r\n\r\n return (\r\n \r\n Bid History\r\n \r\n \r\n
\r\n {vehicleTitle}\r\n
\r\n \r\n VIN: {vehicleVin}\r\n
\r\n \r\n \r\n \r\n \r\n Date | \r\n Time (TIME ZONE {getLocalText('VendorTimeZoneAbbreviation', 'None')}) | \r\n Bid Amount | \r\n Dealership | \r\n
\r\n \r\n \r\n {bidHistories &&\r\n bidHistories.map((item, index) => (\r\n \r\n {DateTime.fromISO(item.CreatedDate).toFormat('ccc LLL dd yyyy', { locale: 'en-US' })} | \r\n {DateTime.fromISO(item.CreatedDate).toFormat('hh:mm:ss a', { locale: 'en-US' })} | \r\n {item.BidAmountString} | \r\n {item.DealerShipName} | \r\n
\r\n ))}\r\n \r\n \r\n \r\n Note: If two users bid the same amount, the first bid takes priority.\r\n \r\n \r\n \r\n )\r\n}\r\n","import { BidsHistoryModal } from 'modules/BuyerActivity/BidsHistoryModal'\r\nimport { StyledAuctionText, StyledNumberOfBids } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { useContext, useState } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\nexport const VehicleBidHistoryLink = () => {\r\n const [showBidsHistory, setShowBidsHistory] = useState(false)\r\n const {\r\n vehicleData: { vehicle: vehicleInfo, auctionInfo }\r\n } = useContext(VehicleContext)\r\n\r\n return (\r\n <>\r\n {auctionInfo && !auctionInfo.IsDirectSale && (\r\n <>\r\n \r\n setShowBidsHistory(true)}>\r\n {auctionInfo.NumberOfBids}\r\n \r\n {' Bids '}\r\n {vehicleInfo.ReserveMet === 1 && (Reserve Met)}\r\n {vehicleInfo.ReserveMet === 0 && (Reserve Not Met)}\r\n \r\n setShowBidsHistory(false)}\r\n size=\"lg\"\r\n centered\r\n auctionInfo={auctionInfo}\r\n vehicleInfo={vehicleInfo}\r\n onClose={() => {\r\n setShowBidsHistory(false)\r\n }}\r\n />\r\n >\r\n )}\r\n >\r\n )\r\n}\r\n","import { StyledNoActivity } from './NoActivity.styled'\r\nimport NoActivityImg from 'images/no-activity.jpg'\r\nimport { StyledVehicleAuctionInfo } from './VehicleAuction.styled'\r\n\r\ninterface IProps {\r\n message: string\r\n}\r\n\r\nconst NoActivity = ({ message }: IProps) => {\r\n return (\r\n \r\n \r\n
\r\n \r\n {message}\r\n
\r\n \r\n \r\n )\r\n}\r\n\r\nexport default NoActivity\r\n","export default \"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAQDAwMDAwQDAwQGBAMEBgcFBAQFBwgGBgcGBggKCAkJCQkICgoMDAwMDAoMDA0NDAwRERERERQUFBQUFBQUFBT/2wBDAQQFBQgHCA8KCg8UDg4OFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCABYAHYDAREAAhEBAxEB/8QAGgABAQEBAQEBAAAAAAAAAAAAAAEEBQMCCP/EADUQAAIBAgIHBgQFBQAAAAAAAAABAgMEEZIFEhQhMVPRExUiQVFScXKRsjM0VGHSIzVCgbH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/ZgAAAAAAAAAAAAAAACrgwIAAAAAAAAAAAAAAAAq4MCAAAADFLSltCcoNTbhJxeEW1jF4MCd623tqZGA71tvbUyMB3rbe2pkYDvW29tTIwPe3u6Vy5KmpLV460dXiB7gAAACrgwIAAAAORZwp1LytGpFTj2lV6rx979MAPedxounOVOVDGUHhLCNRrH4pgTa9E8h5KvUBteieQ8lXqBNr0VyHkq9QPGxuqdCMp1sVrYblFt+fkgOhQvKFzJwpa2KWPijKK9PNAaAAACrgwIAAAAOVYfna3z1fvYCjCnU0hWjUipx15eF4ryXo0BouZ6NtZRhUt8Zz3qMXNvBeb8QHvC3sZxU40IuMlivFP8AkBdls/08c0/5ANls/wBPHNP+QGDRj1q1R4Ybmkl+0gOoAAAVcGBAAAAByrD87W+er97Att/ca3zS/wCIDbWs6FxJTqNxmlhrRw3r03gfCvLOm6lKM8I268TfDct6x82Bitb6rO4lWrNxpVcFGm/8Yrg/i/MDr8QOVor8Wfwl9wHVAAAKuDAgAAAA5cbK/hUq1KS1XOc5RknBvCUm1ueIEsoTheSjVlrVd+u3hx3e3cBsvdslBUrODc57pVcUlCP7YviBgjoq6jBQVHwr1cXj8d4H13decp/WPUDfbRuIU1CvDVcd0Xiniv8AQGHRX4s/hL7gOqAAAVcGBAAAAAA5jtL5XFarRg1rSbjPw8Gl6gOx0z75/Sn0Adjpn3z+lPoA7HTPvn9KfQB2OmffP6U+gHpYWle2nJ1YtJprWeG9t4+QG8AAAq4MCAAAAAAAAAAAAAAAAKuDAgAAAAAAAAAAAAAAACrgwPbYrvkVMrAbHd8iplfQBsd3yKmV9AGx3fIqZX0AbHd8iplfQBsd3yKmV9AGx3fIqZX0Amx3fIqZJdAGx3fIqZJdAGx3fIqZJdAGx3fIqZJdAGx3fIqZJdAGx3fIqZJdAGx3fIqZJdAKrO7wf9Cpkl0A/9k=\"","// import { colorPrimary, textMenuColor } from 'common/theme'\r\nimport { zIndex } from 'common/constants'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledSubMenu = styled.div<{ isSticky?: boolean; assetFolder?: string }>`\r\n box-shadow: 0 0.3rem 0.4rem rgba(0, 0, 0, 0.15);\r\n border-radius: 0.3rem;\r\n background: ${({ isSticky, assetFolder, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.subMenuBackground\r\n }\r\n return theme.headerNotSticky.subMenuBackground\r\n }};\r\n position: absolute;\r\n font-size: 1.4rem;\r\n opacity: 0;\r\n transform: translateY(4rem);\r\n pointer-events: none;\r\n transition: all 167ms ease-in;\r\n z-index: ${zIndex.subMenu};\r\n\r\n &:hover {\r\n display: block;\r\n }\r\n\r\n svg {\r\n margin-right: 1rem;\r\n }\r\n\r\n .nav-item .nav-link {\r\n font-size: 1.6rem;\r\n margin-left: 0;\r\n margin-right: 0;\r\n }\r\n\r\n li {\r\n height: 4.2rem;\r\n transition: 167ms ease-in;\r\n border-bottom: 0.2rem solid transparent;\r\n line-height: 2.2;\r\n }\r\n\r\n li:hover {\r\n border-bottom: 0.2rem solid\r\n ${({ isSticky, theme, assetFolder }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.subMenuItemBorder\r\n }\r\n return theme.headerNotSticky.subMenuItemBorder\r\n }};\r\n border-top: 0.2rem solid\r\n ${({ isSticky, theme, assetFolder }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.subMenuItemBorder\r\n }\r\n return theme.headerNotSticky.subMenuItemBorder\r\n }};\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n box-shadow: none;\r\n border-radius: unset;\r\n transition: none;\r\n transform: unset;\r\n opacity: unset;\r\n position: unset;\r\n background: transparent;\r\n li:hover {\r\n border-bottom: 0.2rem solid transparent;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledSubMenuItem = styled.li<{ isSticky?: boolean; assetFolder?: string }>`\r\n white-space: nowrap;\r\n a.nav-link:hover {\r\n //change nav link hover color: ;\r\n color: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.subMenuItemHover\r\n }\r\n return theme.headerNotSticky.subMenuItemHover\r\n }};\r\n svg {\r\n fill: ${({ isSticky, theme }) => {\r\n if (isSticky) {\r\n return theme.headerSticky.subMenuItemHover\r\n }\r\n return theme.headerNotSticky.subMenuItemHover\r\n }};\r\n }\r\n }\r\n\r\n a.nav-link.active:after {\r\n border-bottom-color: transparent !important;\r\n border-top-color: transparent !important;\r\n }\r\n`\r\n","import { isEmpty } from 'lodash'\r\nimport { IVehicleProperties, IVehicleInfo } from '../types/vehicleTypes'\r\nimport { ISystemSetting } from '../types/baseTypes'\r\nimport { VEHICLE_PROPERTIES_TO_HIDE } from 'common/constants'\r\n\r\nexport const getVehicleDetailProperties = (vehicleInfo: IVehicleInfo, retailView: boolean = false) =>\r\n retailView\r\n ? vehicleInfo?.Properties?.filter((p) => p.ID === 1 && !VEHICLE_PROPERTIES_TO_HIDE.includes(p.UIConstantName))\r\n : vehicleInfo?.Properties?.filter((p) => p.ID === 1)\r\n\r\nexport const processInServiceDateProperty = (\r\n properties: IVehicleProperties[],\r\n vehicleSrcCode: string,\r\n setting: ISystemSetting\r\n) => {\r\n return properties?.filter((p) => {\r\n if (p.UIConstantName !== 'IN_SERVICE_DATE') return true\r\n\r\n /**\r\n * setting\r\n * Value:\r\n * 0 : Hide\r\n * 1 : Show (check setting.ValueString)\r\n *\r\n * ValueString:\r\n * BMWFS : ShowInServiceDateForOffleaseCar\r\n * BMWNA : ShowInServiceDateForCompanyCar\r\n * : ShowInServiceDateForBothOffleaseAndCompanyCars\r\n */\r\n\r\n return (\r\n setting.Value === '1' &&\r\n (isEmpty(setting.ValueString) || setting.ValueString.toLowerCase() === vehicleSrcCode.toLowerCase())\r\n )\r\n })\r\n}\r\n\r\nconst transliterate = (c: string) => {\r\n return '0123456789.ABCDEFGH..JKLMN.P.R..STUVWXYZ'.indexOf(c) % 10\r\n}\r\n\r\nconst get_check_digit = (vin: string) => {\r\n var map = '0123456789X'\r\n var weights = '8765432X098765432'\r\n var sum = 0\r\n for (var i = 0; i < 17; ++i) sum += transliterate(vin[i]) * map.indexOf(weights[i])\r\n return map[sum % 11]\r\n}\r\n\r\nexport const validate = (vin: string) => {\r\n vin = vin.toUpperCase()\r\n if (vin.length !== 17) return false\r\n if (/^(.)\\1+$/.test(vin)) return false\r\n return get_check_digit(vin) === vin[8]\r\n}\r\n","import { smallScreen } from '../../common/theme'\r\nimport styled from 'styled-components'\r\nimport { Carousel } from 'react-bootstrap'\r\nimport classNames from 'classnames'\r\nexport const StyledVehicleDetailImage = styled.div.attrs(({ className }) => ({\r\n className: classNames('text-center text-sm-left pb-4 pb-sm-0', className)\r\n}))`\r\n img {\r\n width: 100%;\r\n display: inline-block;\r\n border-radius: 0.3rem;\r\n max-width: 40rem;\r\n aspect-ratio: 4 / 3;\r\n object-fit: cover;\r\n cursor: pointer;\r\n\r\n @media (max-width: ${smallScreen}) {\r\n width: 100%;\r\n }\r\n }\r\n svg {\r\n width: 75%;\r\n height: 75%;\r\n display: block;\r\n margin: auto;\r\n }\r\n .carousel-item-broken-main-img {\r\n max-width: 25%;\r\n }\r\n`\r\nexport const StyledVehicleDetailCarousel = styled(Carousel)`\r\n svg {\r\n color: ${({ theme }) => theme.colors.primary};\r\n width: 100%;\r\n }\r\n width: 100%;\r\n .carousel-control-prev,\r\n .carousel-control-next {\r\n width: 8%;\r\n opacity: 1;\r\n }\r\n\r\n .carousel-control-prev:hover,\r\n .carousel-control-next:hover {\r\n opacity: 0.5;\r\n }\r\n .carousel-inner {\r\n margin: 0.5rem 10% 0 10%;\r\n width: auto;\r\n }\r\n\r\n img {\r\n cursor: pointer;\r\n }\r\n\r\n .carousel-item-img {\r\n max-width: 25%;\r\n max-height: 4rem;\r\n padding: 0;\r\n }\r\n`\r\n","import { Tooltip } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledVehicleNote = styled.div`\r\n .note-form {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.375rem;\r\n .note-input {\r\n width: 30%;\r\n }\r\n }\r\n .vehicle-note {\r\n text-overflow: ellipsis;\r\n white-space: pre;\r\n overflow: hidden;\r\n max-width: 30rem;\r\n }\r\n .save-vehicle-note {\r\n display: contents;\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-weight: bold;\r\n }\r\n`\r\nexport const StyledToolTip = styled(Tooltip)`\r\n .arrow {\r\n display: none;\r\n }\r\n .tooltip-inner {\r\n white-space: pre-wrap;\r\n background-color: #fff;\r\n color: black;\r\n border: 0.1rem solid #ddd;\r\n border-radius: 0.5rem;\r\n max-width: 30rem;\r\n text-align: start;\r\n }\r\n`\r\n","import styled, { css } from 'styled-components'\r\n\r\nexport const cardStyle = css`\r\n font-size: 1.4rem;\r\n margin: 1.2rem 0;\r\n padding: 2rem;\r\n box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.15);\r\n border-radius: 0.3rem;\r\n transition: 167ms ease-in-out;\r\n\r\n &:hover {\r\n box-shadow: 0 0.4rem 2.4rem rgba(0, 0, 0, 0.1);\r\n }\r\n`\r\nexport const StyledCard = styled.div`\r\n ${cardStyle}\r\n`\r\n","/**\r\n * Author: juliencrn\r\n * Availability: https://usehooks-ts.com/react-hook/use-window-size\r\n */\r\nimport { useEffect, useState } from 'react'\r\n\r\ninterface WindowSize {\r\n width: number\r\n height: number\r\n}\r\n\r\nfunction useWindowSize(): WindowSize {\r\n const [windowSize, setWindowSize] = useState({\r\n width: 0,\r\n height: 0\r\n })\r\n\r\n useEffect(() => {\r\n const handler = () => {\r\n setWindowSize({\r\n width: window.innerWidth,\r\n height: window.innerHeight\r\n })\r\n }\r\n\r\n // Set size at the first client-side load\r\n handler()\r\n\r\n window.addEventListener('resize', handler)\r\n\r\n // Remove event listener on cleanup\r\n return () => {\r\n window.removeEventListener('resize', handler)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n return windowSize\r\n}\r\n\r\nexport default useWindowSize\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport { Col, Row } from 'react-bootstrap'\r\nimport { Link } from 'react-router-dom'\r\nimport styled from 'styled-components'\r\n\r\nexport const RightContainer = styled(Col)`\r\n .main-img {\r\n max-height: 100vh;\r\n object-fit: cover;\r\n object-position: center;\r\n }\r\n .img-corner-right {\r\n position: absolute;\r\n border: 0;\r\n top: 0;\r\n right: 0;\r\n height: 6.5%;\r\n margin-right: 4%;\r\n margin-top: 4%;\r\n }\r\n\r\n .img-corner-left {\r\n position: absolute;\r\n border: 0;\r\n top: 0;\r\n left: 0;\r\n height: 9%;\r\n margin-left: 4%;\r\n margin-top: 4%;\r\n }\r\n`\r\nexport const LayoutContainer = styled(Row)`\r\n font-family: ${(props) => props.theme.fonts.fontBase};\r\n font-size: 1.4rem;\r\n margin-right: 0;\r\n margin-left: 0;\r\n input {\r\n font-size: 1.4rem;\r\n }\r\n\r\n input:-webkit-autofill,\r\n input:-webkit-autofill:hover,\r\n input:-webkit-autofill:focus,\r\n input:-webkit-autofill:active {\r\n -webkit-box-shadow: 0 0 0 3rem white inset;\r\n box-shadow: 0 0 0 3rem white inset;\r\n background: #fff;\r\n }\r\n`\r\nexport const StyledFooter = styled.div`\r\n font-size: 1rem;\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n bottom: 0;\r\n width: 100%;\r\n margin-right: 0;\r\n margin-left: 0;\r\n padding-bottom: 2.5rem;\r\n padding-left: 3rem;\r\n padding-right: 0.5rem;\r\n`\r\n\r\nexport const LinkBaseStyled = styled(Link)`\r\n text-align: center;\r\n display: block;\r\n font-size: 1.4rem;\r\n color: ${({ theme }) => theme.colors.linkColor};\r\n font-weight: 500;\r\n padding-bottom: 0.5rem;\r\n`\r\n\r\nexport const BackToLoginLink = styled(LinkBaseStyled)``\r\n\r\nexport const ClickHereLink = styled(Link)`\r\n color: ${({ theme }) => theme.colors.linkColor};\r\n`\r\n\r\nexport const StyledLoginFormFooter = styled.div`\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n margin-top: 2rem;\r\n align-items: center;\r\n`\r\n\r\nexport const LoginTitle = styled.h1`\r\n color: ${({ theme }) => theme.colors.primary};\r\n text-transform: uppercase;\r\n font-size: 4.2rem;\r\n margin-bottom: 1.2rem;\r\n width: inherit;\r\n`\r\n\r\nexport const ForgotLink = styled.div`\r\n display: flex;\r\n justify-content: end;\r\n margin-bottom: 2rem;\r\n a {\r\n color: ${({ theme }) => theme.colors.linkColor};\r\n }\r\n`\r\n\r\nexport const RightFooterContainer = styled(Col)`\r\n display: flex;\r\n justify-content: end;\r\n margin-right: 2rem;\r\n`\r\nexport const LeftFooterContainer = styled(Col)`\r\n display: flex;\r\n align-items: center;\r\n span {\r\n font-size: 1rem;\r\n }\r\n`\r\n\r\nexport const StyledLeftContainer = styled(Row)`\r\n justify-content: center;\r\n`\r\n\r\nexport const FormLoginBody = styled.div`\r\n width: 100%;\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n align-self: start;\r\n\r\n .btn-primary:disabled {\r\n background-color: ${({ theme }) => theme.colors.colorButtonDisabled};\r\n border-color: ${({ theme }) => theme.colors.colorButtonDisabled};\r\n }\r\n\r\n .text-input-password {\r\n margin-bottom: 0.1rem !important;\r\n }\r\n`\r\n\r\nexport const LoginContainerColStyled = styled(Col)`\r\n display: flex;\r\n align-self: flex-end;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n min-height: 100vh;\r\n\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n min-height: 80vh;\r\n }\r\n`\r\n","import { IconProps } from 'core/typing/IconType'\r\nimport { ThemedSvg } from './ThemedSvg.styled'\r\n\r\nconst ChevronDown = ({ width = '16', height = '16', ...props }: IconProps) => (\r\n \r\n \r\n \r\n)\r\n\r\nexport default ChevronDown\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledNoActivity = styled.div`\r\n display: flex;\r\n\r\n img {\r\n width: 14rem;\r\n height: 12rem;\r\n }\r\n\r\n div {\r\n width: 100%;\r\n margin-left: 2.4rem;\r\n\r\n span {\r\n font-size: 1.6rem;\r\n color: gray;\r\n }\r\n }\r\n`\r\n","import { textColor } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledAuctionTimeRemaining = styled.div<{ color?: string }>`\r\n color: ${({ color }) => color || textColor};\r\n font-size: 1.2rem;\r\n font-weight: 500;\r\n font-family: sans-serif; /*prevent number jumping when time second change */\r\n`\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const Calendar = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { colorWinning, largeScreen } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledRibbon = styled.span<{ backgroundColor: string; textColor: string }>`\r\n position: relative;\r\n line-height: 2rem !important;\r\n\r\n .ribbon {\r\n background-color: ${(props) => props.backgroundColor};\r\n position: relative;\r\n padding: 0 0.5rem;\r\n display: inline-block;\r\n line-height: 1rem;\r\n margin-left: 0.8rem;\r\n }\r\n\r\n .ribbon-title {\r\n line-height: 2rem;\r\n color: #fff;\r\n white-space: nowrap;\r\n\r\n color: ${(props) => props.textColor};\r\n font-weight: bold;\r\n }\r\n\r\n .ribbon-tail {\r\n position: absolute;\r\n top: 0;\r\n right: -1rem;\r\n }\r\n\r\n .ribbon-tail:after,\r\n .ribbon-tail:before {\r\n content: '';\r\n width: 0;\r\n height: 0;\r\n display: block;\r\n }\r\n\r\n .ribbon-tail:after {\r\n border-right: 1rem solid transparent;\r\n border-bottom: 1rem solid ${(props) => props.backgroundColor};\r\n }\r\n\r\n .ribbon-tail:before {\r\n border-right: 1rem solid transparent;\r\n border-top: 1rem solid ${(props) => props.backgroundColor};\r\n }\r\n\r\n @media (max-width: ${largeScreen}) {\r\n .ribbon {\r\n margin-left: 0;\r\n }\r\n }\r\n\r\n @media print {\r\n text-decoration: none;\r\n .ribbon {\r\n background-color: ${(props) => props.backgroundColor};\r\n -webkit-print-color-adjust: exact;\r\n }\r\n .ribbon-tail {\r\n position: absolute;\r\n top: 0;\r\n right: -1rem;\r\n }\r\n }\r\n &&.clickable {\r\n cursor: pointer;\r\n }\r\n`\r\n","import { StyledAuctionText } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { useContext } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\nexport const UserMaxBid = () => {\r\n const {\r\n vehicleData: { auctionInfo }\r\n } = useContext(VehicleContext)\r\n\r\n return (\r\n <>\r\n {auctionInfo?.CanBid && auctionInfo.UserMaxBid !== 0 && (\r\n \r\n Your Max Bid: \r\n {auctionInfo.UserMaxBidString}\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { PropsWithChildren } from 'react'\r\n\r\ninterface IProps extends PropsWithChildren> {\r\n href: string\r\n displayText?: string\r\n}\r\n\r\nexport const PopupLink = ({ href, displayText, children, onClick, ...props }: IProps) => {\r\n const openPopup = (e, url: string) => {\r\n e.preventDefault()\r\n\r\n var width = window.screen.width / 2\r\n var height = window.screen.height / 2\r\n\r\n window.open(\r\n url,\r\n '_blank',\r\n `directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=${width},height=${height}`\r\n )\r\n }\r\n\r\n return (\r\n {\r\n onClick?.(e)\r\n openPopup(e, href)\r\n }}\r\n {...props}\r\n >\r\n {children}\r\n \r\n )\r\n}\r\n","import { zIndex } from 'common/constants'\r\nimport { mediumScreen, smallScreen } from 'common/theme'\r\nimport { HomeSectionHeader } from 'components/Header/HomeSectionHeader'\r\nimport { headerAnimation, StickyProp } from 'layouts/Layout.styled'\r\nimport styled, { css } from 'styled-components'\r\n\r\nexport const StyledVehicleStickyBar = styled(HomeSectionHeader)`\r\n position: sticky;\r\n z-index: ${({ isSticky }) => (isSticky ? zIndex.stickyHeader : zIndex.pageHeader)};\r\n background: #fff;\r\n\r\n ${({ isSticky }) => (isSticky ? headerAnimation : null)};\r\n ${({ isSticky, theme }) =>\r\n isSticky &&\r\n css`\r\n top: 7.2rem;\r\n\r\n @media (max-width: ${smallScreen}) {\r\n top: 6rem;\r\n }\r\n\r\n .header-row {\r\n height: 4.2rem;\r\n white-space: nowrap;\r\n }\r\n .filter-icon {\r\n color: ${theme.colors.primary};\r\n }\r\n .header-toggle {\r\n background: #fff;\r\n color: ${theme.colors.primary};\r\n box-shadow: none;\r\n justify-content: flex-start;\r\n margin-left: 1rem;\r\n }\r\n\r\n @media (max-width: ${mediumScreen}) {\r\n .header-section {\r\n padding: 0;\r\n margin: 0;\r\n }\r\n .header-col,\r\n .right-action-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n }\r\n }\r\n `};\r\n`\r\n","import { StyledSlideOut } from './SlideOut.styled'\r\nimport { default as PrismSlideOut } from '@prism/slideout'\r\nimport { PropsWithChildren } from 'react'\r\n\r\ninterface IProps extends PropsWithChildren<{}> {\r\n isOpen: boolean\r\n onCloseButtonClick: () => void\r\n placement?: 'left' | 'right'\r\n}\r\nexport const SlideOut = ({ isOpen, onCloseButtonClick, children, placement = 'right' }: IProps) => {\r\n return (\r\n \r\n \r\n {children}\r\n \r\n \r\n )\r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const DriveTrain = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const Transmission = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const SaleChannel = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const ExteriorColor = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { ThemedSvg } from './ThemedSvg.styled'\r\nimport { IconProps } from 'core/typing/IconType'\r\n\r\nexport const InteriorColor = ({ width = '16px', height = '16px', color = 'currentColor' }: IconProps) => {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { IconSvg } from '@prism/icon'\r\nimport { DriveTrain } from 'icons/DriveTrain'\r\nimport { Transmission } from 'icons/Transmission'\r\nimport { SaleChannel } from 'icons/SaleChannel'\r\nimport { ExteriorColor } from 'icons/ExteriorColor'\r\nimport { InteriorColor } from 'icons/InteriorColor'\r\nimport { Calendar } from 'icons/Calendar'\r\nimport { isEmpty } from 'lodash'\r\n\r\nexport const getVehicleListingInfoIcon = (name: string) => {\r\n if (isEmpty(name)) return ''\r\n\r\n switch (name) {\r\n case 'DD_CONDITION':\r\n return 'CR:'\r\n case 'MILEAGE':\r\n return \r\n case 'VEHICLE_LOCATION':\r\n return \r\n case 'EXTERIOR_COLOUR':\r\n return \r\n case 'INTERIOR_TRIM':\r\n return \r\n case 'DRIVETRAIN':\r\n return \r\n case 'TRANSMISSION':\r\n return \r\n case 'SALE_CHANNEL':\r\n return \r\n case 'IN_SERVICE_DATE':\r\n return \r\n\r\n default:\r\n return ''\r\n }\r\n}\r\n","import classNames from 'classnames'\r\nimport { getVehicleListingInfoIcon } from 'common/vehicleListingInfoIcons'\r\nimport { PopupLink } from 'components/Share/PopupLink'\r\nimport { isEmpty } from 'lodash'\r\nimport { useContext, useState } from 'react'\r\nimport { Button, Col, Row } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport styled from 'styled-components'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { buildMMRUrl } from 'utils/urlUtils'\r\n\r\nimport { StyledInfoLabel } from './VehicleDetails.styled'\r\nimport { ISystemSetting } from 'types/baseTypes'\r\nimport { getVehicleDetailProperties, processInServiceDateProperty } from '../../utils/vehicleUtils'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\ninterface IProps {\r\n vehicleInfo: IVehicleInfo\r\n fieldLimit?: number\r\n}\r\n\r\nexport const StyledVehicleProperties = styled.div``\r\n\r\nexport const VehicleProperties = ({ vehicleInfo, fieldLimit }: IProps) => {\r\n const {\r\n appSettings: { MMRUrl },\r\n getSystemSetting\r\n } = useGlobalStore()\r\n\r\n const showInServiceDateSetting = getSystemSetting('SHOW_INSERVICEDATE_VECHILESOURCE') as ISystemSetting\r\n const { retailView } = useContext(VehicleContext)\r\n\r\n const [showAll, setShowAll] = useState(false)\r\n const properties = processInServiceDateProperty(\r\n getVehicleDetailProperties(vehicleInfo, retailView),\r\n vehicleInfo.SourceCode,\r\n showInServiceDateSetting\r\n )\r\n\r\n const limit = fieldLimit > 0 ? fieldLimit : properties?.length\r\n\r\n const toggleDisplay = () => {\r\n setShowAll((show) => !show)\r\n }\r\n\r\n return (\r\n \r\n \r\n <>\r\n {properties?.slice(0, showAll ? properties?.length : limit).map((x, idx) => (\r\n \r\n \r\n {!isEmpty(getVehicleListingInfoIcon(x.UIConstantName)) ? (\r\n <>{getVehicleListingInfoIcon(x.UIConstantName)}>\r\n ) : (\r\n `${x.Code}:`\r\n )}\r\n \r\n {x.Code === 'MMR' ? (\r\n \r\n {x.Description}\r\n \r\n ) : (\r\n {`${!isEmpty(x.Description) ? x.Description : 'N/A'}`}\r\n )}\r\n \r\n ))}\r\n >\r\n\r\n {limit < properties?.length && (\r\n \r\n \r\n \r\n )}\r\n
\r\n \r\n )\r\n}\r\n","import { colorDanger, textColorLight } from 'common/theme'\r\nimport { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyleDisclosureModal = styled(Modal)`\r\n padding: 1rem 1.5rem;\r\n font-size: 1.6rem;\r\n .modal-content {\r\n box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.15);\r\n border-radius: 0.3rem;\r\n }\r\n button {\r\n margin: 0.5rem;\r\n align-content: center;\r\n }\r\n .modal-header {\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n color: white;\r\n font-size: 1.8rem;\r\n .close span {\r\n font-size: 2rem;\r\n font-weight: normal;\r\n color: white;\r\n }\r\n }\r\n .modal-body {\r\n color: ${textColorLight};\r\n .document-link {\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n }\r\n }\r\n .modal-footer {\r\n border: none;\r\n justify-content: center;\r\n }\r\n`\r\nexport const StyleDisclosureWarningSpan = styled.p`\r\n font-size: 1.6rem;\r\n color: ${colorDanger};\r\n font-weight: bold;\r\n`\r\n","import { saveDisclosure } from 'apis/vehicleApis'\r\nimport { useState } from 'react'\r\nimport { Modal } from 'react-bootstrap'\r\nimport { IDocumentSignInfor, IVehicleInfo } from 'types/vehicleTypes'\r\nimport { StyledAuctionButton } from './VehicleAuction.styled'\r\nimport { StyleDisclosureWarningSpan } from './VehicleDisclosureModal.styled'\r\nimport styled from 'styled-components'\r\n\r\nconst StyledDisclosureModalBody = styled(Modal.Body)`\r\n & > * + * {\r\n margin-top: 1.5rem;\r\n }\r\n`\r\n\r\ninterface IBidsHistoryProps {\r\n vehicleInfo: IVehicleInfo\r\n documentSignInfo: IDocumentSignInfor\r\n handleSubmitSuccess: () => void\r\n onClose: () => void\r\n}\r\n\r\nexport const VehicleDisclosureModal = ({\r\n vehicleInfo,\r\n documentSignInfo,\r\n handleSubmitSuccess,\r\n onClose\r\n}: IBidsHistoryProps) => {\r\n const [enableDisclosureButtons, setEnableDisclosureButtons] = useState(false)\r\n const [displayDisclosureError, setDisplayDisclosureError] = useState(false)\r\n const enableDisclosureControl = () => {\r\n setEnableDisclosureButtons(true)\r\n window.open(\r\n '/resource/GetVehicleInstanceDocumentByID?documentID=' + documentSignInfo.VehicleInstanceDocumentsID,\r\n \"_parent'\"\r\n )\r\n }\r\n\r\n const acceptDisclosure = async () => {\r\n setDisplayDisclosureError(false)\r\n try {\r\n const response = await saveDisclosure(documentSignInfo)\r\n if (response.Value === 0) {\r\n handleSubmitSuccess()\r\n } else {\r\n setDisplayDisclosureError(true)\r\n setEnableDisclosureButtons(true)\r\n }\r\n onClose()\r\n } catch (error) {\r\n console.log('SAVE DISCLOSURE ERROR: ' + error)\r\n setDisplayDisclosureError(true)\r\n }\r\n }\r\n return (\r\n <>\r\n Vehicle Disclosure Information\r\n \r\n \r\n VIN: {vehicleInfo.VIN}\r\n
\r\n \r\n \r\n Prior Use Disclosure: By clicking \"Accept\", I acknowledge I have received and reviewed the above listed\r\n disclosure document and forfeit any right to arbitrate any dispute based upon the condition stated in this\r\n disclosure.\r\n \r\n \r\n Note: Users can only proceed with the bidding/buying process after reviewing and accepting the disclosure\r\n document\r\n \r\n {displayDisclosureError && (\r\n Request failed. Please try again.\r\n )}\r\n \r\n \r\n acceptDisclosure()}>\r\n Accept\r\n \r\n onClose()}>\r\n Decline\r\n \r\n \r\n >\r\n )\r\n}\r\n","import { hideVehicleBidRow } from 'apis/vehicleApis'\r\nimport { VehicleStatuses } from 'common/constants'\r\nimport { AlertDialog } from 'components/AlertDialog/AlertDialog'\r\nimport {\r\n BuyItNowButtonContainer,\r\n BuyItNowButtonGroup,\r\n StyledAuctionButton,\r\n StyledAuctionText\r\n} from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { VehicleDisclosureModal } from 'modules/BuyerActivity/VehicleDisclosureModal'\r\nimport { StyleDisclosureModal } from 'modules/BuyerActivity/VehicleDisclosureModal.styled'\r\nimport { TextDanger } from 'components/Forms'\r\nimport { useCountdown } from 'hooks/useCountdown'\r\nimport { useContext, useEffect, useState } from 'react'\r\nimport { useBiddingSidePanel } from 'store/useBiddingSidePanelStore'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { VehicleAction } from 'types/vehicleTypes'\r\nimport { VehicleContext } from './VehicleContext'\r\n\r\nexport const VehicleBidBuyActions = () => {\r\n const { getBaseVehicle } = useVehicleStore()\r\n\r\n const setBiddingVehicleInstanceId = useBiddingSidePanel((state) => state.setBiddingVehicleInstanceId)\r\n const {\r\n vehicleData: { vehicle: vehicleInfo, auctionInfo, documentSignInfo },\r\n vehicleData,\r\n onRemoveBid,\r\n showRemoveBid,\r\n errorMessage\r\n } = useContext(VehicleContext)\r\n\r\n const [showVehicleDisclosureConfirm, setShowVehicleDisclosureConfirm] = useState(false)\r\n const [bidButtonAction, setBidButtonAction] = useState(null)\r\n const [modalShow, setModalShow] = useState(false)\r\n\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n const { seconds: timeOut } = useCountdown(auctionInfo?.EndDate)\r\n const getSystemSettings = useGlobalStore((state) => state.getSystemSetting)\r\n const [showErrorMsg, setShowErrorMsg] = useState(false)\r\n const { acceptVehicleDocumentSignInfo } = useVehicleStore((state) => state)\r\n\r\n useEffect(() => {\r\n if (timeOut === 0 && auctionInfo?.IsHighestBidder) {\r\n getBaseVehicle(vehicleData)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [timeOut, auctionInfo?.IsHighestBidder])\r\n\r\n const isShowBuyItNowPrice =\r\n auctionInfo && !auctionInfo.IsDirectSale && vehicleInfo.BuyItNowPrice > auctionInfo.CurrentPrice\r\n\r\n const handleDisclosureAccepted = () => {\r\n setShowVehicleDisclosureConfirm(false)\r\n acceptVehicleDocumentSignInfo({ vehicleInstanceID: vehicleInfo?.InstanceID, documentSignInfo: documentSignInfo })\r\n if (bidButtonAction === VehicleAction.BID) {\r\n setBiddingVehicleInstanceId(vehicleInfo.InstanceID)\r\n } else {\r\n window.open('/vehicles#buyItNow/' + vehicleInfo.InstanceID, '_self')\r\n }\r\n }\r\n\r\n const haveToAcceptDisclosure = vehicleInfo.DisclosurePresent && documentSignInfo && !documentSignInfo?.IsAccepted\r\n\r\n const removeBidVehicle = async (auctionInfo: any) => {\r\n try {\r\n const response = await hideVehicleBidRow(auctionInfo)\r\n\r\n if (response?.Success) {\r\n onRemoveBid?.()\r\n } else {\r\n setShowErrorMsg(true)\r\n }\r\n } catch (error) {\r\n setShowErrorMsg(true)\r\n } finally {\r\n setModalShow(false)\r\n }\r\n }\r\n\r\n if (vehicleInfo.StatusID === VehicleStatuses.SoldNotFunded || !auctionInfo) {\r\n return null\r\n }\r\n\r\n return (\r\n <>\r\n setModalShow(false)}\r\n onSave={() => removeBidVehicle(auctionInfo)}\r\n isConfirmation={true}\r\n />\r\n\r\n setShowVehicleDisclosureConfirm(false)}\r\n size=\"md\"\r\n centered\r\n >\r\n handleDisclosureAccepted()}\r\n onClose={() => {\r\n setShowVehicleDisclosureConfirm(false)\r\n }}\r\n />\r\n \r\n {auctionInfo?.CanBid && timeOut > 0 && vehicleInfo.StatusID === VehicleStatuses.OnSale && (\r\n <>\r\n {showRemoveBid &&\r\n auctionInfo.HasPreviousBid &&\r\n !auctionInfo.IsHighestBidder &&\r\n getSystemSettings('ADD_OR_REMOVE_BID_BUTTON_ON_BIDS_SCREEN') === '1' && (\r\n setModalShow(true)}>\r\n {getLocalText('REMOVE_VEHICLE', 'Remove This Vehicle')}\r\n \r\n )}\r\n {\r\n if (!auctionInfo.HasPreviousBid && haveToAcceptDisclosure) {\r\n setBidButtonAction(VehicleAction.BID)\r\n setShowVehicleDisclosureConfirm(true)\r\n } else {\r\n setBiddingVehicleInstanceId(vehicleInfo.InstanceID)\r\n }\r\n }}\r\n >\r\n \r\n {auctionInfo.HasPreviousBid ? getLocalText('BID_AGAIN', 'Bid Again') : getLocalText('BID', 'Bid')}\r\n \r\n \r\n\r\n \r\n {auctionInfo?.CanBuy && (\r\n \r\n {isShowBuyItNowPrice && (\r\n \r\n Buy It Now Price: {auctionInfo.BuyItNowPriceString}\r\n \r\n )}\r\n\r\n {!auctionInfo.IsDirectSale && (\r\n {\r\n if (haveToAcceptDisclosure) {\r\n setBidButtonAction(VehicleAction.BUY)\r\n setShowVehicleDisclosureConfirm(true)\r\n } else {\r\n window.open('/vehicles#buyItNow/' + vehicleInfo.InstanceID, '_self')\r\n }\r\n }}\r\n >\r\n Buy It Now\r\n \r\n )}\r\n \r\n )}\r\n \r\n\r\n {showErrorMsg && {errorMessage}}\r\n >\r\n )}\r\n >\r\n )\r\n}\r\n","import { colorWatching, colorWinning, smallScreen, textColor } from 'common/theme'\r\nimport { StyledCard } from 'components/Share/Card.styled'\r\nimport { Card, Modal, Row, Popover, Button } from 'react-bootstrap'\r\nimport styled, { css } from 'styled-components'\r\n\r\nexport const BuyItNowButtonGroup = styled.div``\r\n\r\nexport const StyledAuctionCardRow = styled(Row).attrs({\r\n className: 'no-gutters'\r\n})``\r\n\r\nexport const StyledAuctionImage = styled.div.attrs({\r\n className: 'text-center text-sm-left pb-4 pb-sm-0'\r\n})`\r\n img {\r\n width: 90%;\r\n display: inline-block;\r\n border-radius: 0.3rem;\r\n\r\n @media (max-width: ${smallScreen}) {\r\n width: 100%;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledAuctionTitle = styled(Card.Text)`\r\n font-weight: 600;\r\n font-size: 1.6rem;\r\n a {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n margin-bottom: 0.2rem;\r\n line-height: 1.3;\r\n`\r\n\r\nexport const StyledAuctionText = styled.div`\r\n font-size: 1.2rem;\r\n color: ${textColor};\r\n\r\n span,\r\n .invoice-field {\r\n font-weight: 600;\r\n }\r\n a {\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n cursor: pointer;\r\n }\r\n\r\n .reserve {\r\n white-space: nowrap;\r\n font-weight: 300;\r\n }\r\n`\r\n\r\nexport const StyledAuctionPrice = styled.div`\r\n font-size: 2.4rem;\r\n font-weight: bold;\r\n`\r\n\r\nconst StyleBaseTag = css`\r\n font-size: 1.2rem;\r\n text-transform: uppercase;\r\n text-align: center;\r\n color: #fff;\r\n background: #999;\r\n display: inline-block;\r\n\r\n padding: 0.4rem;\r\n position: relative;\r\n\r\n span {\r\n padding-right: 0.5rem;\r\n }\r\n\r\n ::before,\r\n ::after {\r\n content: '';\r\n height: 100%;\r\n\r\n position: absolute;\r\n top: 0;\r\n\r\n border-top: 1.3rem solid transparent;\r\n border-bottom: 1.3rem solid transparent;\r\n }\r\n\r\n ::before {\r\n left: -1.3rem;\r\n display: inline-block;\r\n\r\n border-right: 1.3rem solid #999;\r\n }\r\n\r\n ::after {\r\n right: -1.3rem;\r\n display: none;\r\n\r\n border-left: 1.3rem solid #999;\r\n }\r\n`\r\n\r\nexport const StyledTag = styled.div<{ color?: string }>`\r\n ${StyleBaseTag};\r\n background: ${({ color }) => color || colorWatching};\r\n padding: 0.3rem 2rem;\r\n margin: 0.2rem 0;\r\n\r\n ::before {\r\n border-right: 2rem solid ${({ color }) => color || colorWatching};\r\n left: -2rem;\r\n border-top: 1.2rem solid transparent;\r\n border-bottom: 1.2rem solid;\r\n color: transparent;\r\n }\r\n\r\n &.right {\r\n margin-right: 1.5rem;\r\n &::before {\r\n display: none;\r\n }\r\n &::after {\r\n display: inline-block;\r\n border-left: 2rem solid ${({ color }) => color || colorWatching};\r\n right: -2rem;\r\n border-top: 1.2rem solid transparent;\r\n border-bottom: 1.2rem solid;\r\n color: transparent;\r\n }\r\n }\r\n\r\n @media print {\r\n ::before {\r\n padding-left: 0.1rem;\r\n }\r\n background-color: ${({ color }) => color || colorWatching};\r\n -webkit-print-color-adjust: exact;\r\n }\r\n`\r\n\r\nexport const StyledEasyBidPopover = styled(Popover)`\r\n max-width: none;\r\n`\r\ninterface IStyledNumberOfBidsProps {\r\n count?: number\r\n}\r\n\r\nexport const StyledNumberOfBids = styled.a`\r\n ${({ count }) =>\r\n count === 0 &&\r\n `\r\n pointer-events: none;\r\n cursor: default;\r\n text-decoration: none;\r\n color: ${textColor} !important; \r\n `}\r\n`\r\ninterface IStyledReserveMetLabelProps {\r\n isReserveMet?: number\r\n}\r\n\r\nexport const StyledReserveMetLabel = styled.label`\r\n ${({ isReserveMet }) =>\r\n isReserveMet === 1 &&\r\n `\r\n color: ${colorWinning}; \r\n font-weight: 600;\r\n`}\r\n`\r\nexport const StyledAuctionButton = styled(Button)`\r\n font-size: 1.6rem;\r\n min-width: 16rem;\r\n margin: 0.5rem 0 0 0.5rem;\r\n @media (max-width: ${smallScreen}) {\r\n margin: 1rem 0 0 0;\r\n }\r\n`\r\n\r\nexport const BuyItNowButtonContainer = styled.div`\r\n column-gap: 0.5rem;\r\n padding-top: 1rem;\r\n`\r\n\r\nexport const BidSectionContainer = styled.div`\r\n margin-top: 0.5rem;\r\n`\r\n\r\nexport const StyleCurrentBidSection = styled.div`\r\n margin-top: 0.5em;\r\n`\r\n\r\nexport const StyledVehicleBidBuyInformation = styled.div`\r\n text-align: right;\r\n font-size: 1.4rem;\r\n\r\n @media (max-width: ${smallScreen}) {\r\n button {\r\n width: 100%;\r\n }\r\n }\r\n @media (min-width: ${smallScreen}) {\r\n display: flex;\r\n justify-content: space-between;\r\n flex-direction: column;\r\n height: 100%;\r\n }\r\n\r\n ${BidSectionContainer}, .v-timer, .details-grid {\r\n @media print {\r\n display: none;\r\n }\r\n }\r\n`\r\nexport const StyledVehicleAuctionInfo = styled(StyledCard)`\r\n min-height: 17rem;\r\n padding: 2.2rem;\r\n margin-bottom: 2.4rem;\r\n background-color: white;\r\n\r\n .dashboard-auction-button button {\r\n max-width: 45%;\r\n }\r\n .dashboard-reserver-bid {\r\n button {\r\n @media (min-width: ${smallScreen}) {\r\n width: 10rem;\r\n height: 4.5rem;\r\n }\r\n }\r\n ${StyledAuctionText} {\r\n display: inline;\r\n }\r\n }\r\n ${StyledAuctionPrice} {\r\n font-size: 1.6rem;\r\n }\r\n .dashboard-reserver-bid {\r\n ${StyledAuctionText} {\r\n display: inline;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledNoAvailable = styled.div`\r\n font-size: 2.4rem;\r\n font-weight: bold;\r\n color: red;\r\n`\r\n","import { Button, Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const ModalSelectView = styled(Modal)`\r\n .modal-header {\r\n border-bottom: none;\r\n color: white;\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n font-weight: 200;\r\n font-size: 1.85rem;\r\n }\r\n .modal-body {\r\n padding-bottom: 1rem;\r\n padding-top: 1.5rem;\r\n }\r\n\r\n .container-fluid {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n }\r\n`\r\n\r\nexport const ButtonPopup = styled(Button)`\r\n padding: 1rem;\r\n font-size: 1.4rem;\r\n width: 70px;\r\n margin-top: 1rem;\r\n line-height: 0.5;\r\n`\r\n\r\nexport const ConfirmationGroupButton = styled.div`\r\n display: flex;\r\n gap: 1rem;\r\n`\r\n","import { ButtonPopup, ConfirmationGroupButton, ModalSelectView } from 'components/AlertDialog/AlertDialog.styled'\r\nimport React from 'react'\r\nimport { Container, Modal, ModalProps, Row } from 'react-bootstrap'\r\n\r\ninterface IProps extends ModalProps {\r\n title?: string\r\n description?: string\r\n onHide: () => void\r\n onSave?: (request: any) => Promise\r\n isConfirmation?: boolean\r\n}\r\n\r\nexport const AlertDialog = ({ title, description, isConfirmation = false, onHide, onSave, ...props }: IProps) => {\r\n return (\r\n \r\n \r\n {title}\r\n \r\n \r\n \r\n {description}
\r\n \r\n {isConfirmation ? (\r\n \r\n \r\n No\r\n \r\n \r\n Yes\r\n \r\n \r\n ) : (\r\n \r\n OK\r\n \r\n )}\r\n
\r\n \r\n \r\n \r\n )\r\n}\r\n","import { useCountdown } from 'hooks/useCountdown'\r\nimport { StyledAuctionTimeRemaining } from './CountDown.styled'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\n\r\ninterface IProps {\r\n endDate: string | Date\r\n color?: string\r\n}\r\n\r\nexport const CountDown = ({ endDate, color }: IProps) => {\r\n const getSystemSettings = useGlobalStore((state) => state.getSystemSetting)\r\n const minuteToShowSecond = (getSystemSettings('SHOW_SECONDS_AT_MINUTE') as number) ?? 5\r\n\r\n const { seconds } = useCountdown(endDate)\r\n const d = Math.floor(seconds / (3600 * 24))\r\n const h = Math.floor((seconds % (3600 * 24)) / 3600)\r\n const m = Math.floor((seconds % 3600) / 60)\r\n const s = Math.floor(seconds % 60)\r\n\r\n let displayTime = ''\r\n if (d) {\r\n displayTime += `${d}d `\r\n }\r\n if (h) {\r\n displayTime += `${h}h `\r\n }\r\n if (m) {\r\n displayTime += `${m}m `\r\n }\r\n if (seconds < minuteToShowSecond * 60) displayTime += `0${s}s`.slice(-3)\r\n\r\n return (\r\n seconds > 0 && (\r\n \r\n {displayTime} left\r\n \r\n )\r\n )\r\n}\r\n","import { IAuctionInfo } from 'types/auctionTypes'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport { colorDanger, colorWarning, colorWinning, textColor } from 'common/theme'\r\nimport { VehicleStatuses } from 'common/constants'\r\nimport { CountDown } from './CountDown'\r\n\r\ninterface IProps {\r\n vehicleInfo: IVehicleInfo\r\n auctionInfo: IAuctionInfo\r\n}\r\nexport const CountDownWithColor = ({ vehicleInfo, auctionInfo }: IProps) => {\r\n const timeRemainingColor = () => {\r\n if (auctionInfo.HasPreviousBid && auctionInfo.IsHighestBidder) return colorWinning\r\n if (auctionInfo.HasPreviousBid && !auctionInfo.IsHighestBidder) return colorDanger\r\n if (auctionInfo.IsDirectSale && vehicleInfo.OfferID === 0) return colorWarning\r\n return textColor\r\n }\r\n\r\n return (\r\n <>\r\n {vehicleInfo.StatusID !== VehicleStatuses.SoldNotFunded && auctionInfo && (\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledSelect = styled.div`\r\n .react-select {\r\n &__dropdown-indicator {\r\n padding: 0 8px;\r\n }\r\n\r\n &__control {\r\n min-height: 29px;\r\n }\r\n\r\n .check-option &__option {\r\n color: #000;\r\n }\r\n\r\n .check-option &__option:hover {\r\n background-color: ${({ theme }) => theme.colors.dropdownHoverColor};\r\n }\r\n\r\n &__menu .check-option .react-select__option--is-selected {\r\n background-color: transparent;\r\n color: #000;\r\n &:hover {\r\n background-color: ${({ theme }) => theme.colors.dropdownHoverColor};\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyledSelectAll = styled.div`\r\n &:hover {\r\n background-color: ${({ theme }) => theme.colors.dropdownHoverColor};\r\n }\r\n input {\r\n margin-right: 4px;\r\n }\r\n`\r\n","import { ComponentProps } from 'react'\r\nimport ReactSelect from 'react-select'\r\nimport { useTheme } from 'styled-components'\r\nimport { StyledSelect } from './Select.styled'\r\nimport { zIndex } from 'common/constants'\r\n\r\nexport const Select = ({ ...props }: ComponentProps) => {\r\n const {\r\n colors: { primary }\r\n } = useTheme()\r\n\r\n return (\r\n \r\n ({ ...base, zIndex: zIndex.floatingControls }) }}\r\n classNamePrefix=\"react-select\"\r\n {...props}\r\n theme={(theme) => ({\r\n ...theme,\r\n colors: {\r\n ...theme.colors,\r\n primary: primary\r\n }\r\n })}\r\n />\r\n \r\n )\r\n}\r\n\r\nexport default Select\r\n","import { addVehicleNotes } from 'apis/vehicleApis'\r\nimport { Formik } from 'formik'\r\nimport { useClickOutSide } from 'hooks/useClickOutSide'\r\nimport { useContext, useRef, useState } from 'react'\r\nimport { Form, OverlayTrigger, Spinner } from 'react-bootstrap'\r\nimport { StyledInfoLabel } from './VehicleDetails.styled'\r\nimport { StyledToolTip, StyledVehicleNote } from './VehicleNote.styled'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { faPencilAlt } from '@fortawesome/free-solid-svg-icons'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport produce from 'immer'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\n\r\nexport const VehicleNote = () => {\r\n const {\r\n editingNote,\r\n setEditingNote,\r\n vehicleData,\r\n vehicleData: {\r\n vehicle: { VehicleNote, InstanceID, NoteId }\r\n }\r\n } = useContext(VehicleContext)\r\n const editingFormRef = useRef(null)\r\n useClickOutSide(editingFormRef, () => setEditingNote(false))\r\n const [loading, setLoading] = useState(false)\r\n const updateVehicleData = useVehicleStore((state) => state.updateVehicleData)\r\n\r\n const { userInteraction } = useDtmAnalytics()\r\n\r\n const addVehicleNote = async (note: string) => {\r\n try {\r\n setLoading(true)\r\n await addVehicleNotes({\r\n VehicleInstanceID: InstanceID,\r\n NotesId: NoteId,\r\n Notes: note\r\n })\r\n\r\n updateVehicleData(\r\n produce(vehicleData, (draft) => {\r\n draft.vehicle.VehicleNote = note\r\n })\r\n )\r\n setEditingNote(false)\r\n } catch {\r\n } finally {\r\n setLoading(false)\r\n }\r\n\r\n userInteraction(\r\n `${window.webData.pageName} : save note`,\r\n [{ auctionInfo: vehicleData.auctionInfo, VIN: vehicleData.vehicle.VIN }],\r\n { userNote: note }\r\n )\r\n }\r\n\r\n return (\r\n \r\n {editingNote ? (\r\n \r\n addVehicleNote(values.VehicleNote)}\r\n >\r\n {(props) => (\r\n \r\n {loading ? (\r\n \r\n ) : (\r\n \r\n )}\r\n \r\n )}\r\n \r\n
\r\n ) : (\r\n <>\r\n {VehicleNote && !loading && (\r\n \r\n \r\n \r\n \r\n \r\n {VehicleNote}\r\n \r\n }\r\n >\r\n {` ${VehicleNote}`}\r\n \r\n
\r\n )}\r\n >\r\n )}\r\n \r\n )\r\n}\r\n","import { useEffect } from 'react'\r\n\r\nexport const useClickOutSide = (ref: React.MutableRefObject, clickOutsideHandler: () => void) => {\r\n useEffect(() => {\r\n function handleClickOutside(event) {\r\n if (ref.current && !ref.current.contains(event.target)) {\r\n clickOutsideHandler()\r\n }\r\n }\r\n document.addEventListener('mousedown', handleClickOutside)\r\n return () => {\r\n document.removeEventListener('mousedown', handleClickOutside)\r\n }\r\n }, [clickOutsideHandler, ref])\r\n}\r\n","import { Ribbon } from 'components/Ribbon/Ribbon'\r\nimport { IVDPSearchParams } from 'types/ISearchParams'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport { parseUrlSearchParams } from 'utils/urlParams'\r\nimport { StyledRibbonContainer } from './VehicleDetails.styled'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { useContext } from 'react'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport FileSaver from 'file-saver'\r\n\r\ninterface IProps {\r\n vehicleInfo: IVehicleInfo\r\n}\r\n\r\nexport const VehicleRibbons = ({ vehicleInfo }: IProps) => {\r\n const location = useLocation()\r\n const { retailView } = useContext(VehicleContext)\r\n const isVDPHistory = parseUrlSearchParams(location.search).history === 'true'\r\n const showPriceReduction = !isVDPHistory && vehicleInfo.DecreasedPrice\r\n const showNewInventory = !isVDPHistory && vehicleInfo.NewInventory\r\n const showPromotions = !isVDPHistory && !retailView\r\n const { vehicleData } = useContext(VehicleContext)\r\n\r\n return (\r\n \r\n {showPriceReduction && }\r\n {showNewInventory && }\r\n {vehicleInfo.DisclosurePresent && (\r\n \r\n FileSaver.saveAs(\r\n '/resource/GetVehicleInstanceDocumentByID?documentID=' +\r\n vehicleData.documentSignInfo.VehicleInstanceDocumentsID\r\n )\r\n : null\r\n }\r\n title={vehicleData.documentSignInfo ? 'Click Here to View Disclosure' : ''}\r\n />\r\n )}\r\n {showPromotions &&\r\n vehicleInfo.Incentives?.map((i, idx) => )}\r\n \r\n )\r\n}\r\n","import { NavLink } from 'components/Share/Link'\r\nimport { useContext } from 'react'\r\nimport { IVehicleData } from 'types/vehicleTypes'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\nimport { getVdpUrl } from 'utils/urlUtils'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport { StyledTitleSection, TitleVDP } from './VehicleDetails.styled'\r\nimport { VehicleRibbons } from './VehicleRibbons'\r\nimport { SessionStorageKey } from 'common/constants'\r\ninterface IProps {\r\n vehicleData: IVehicleData\r\n}\r\n\r\nexport const VehicleTitleSection = ({ vehicleData }: IProps) => {\r\n const { isVDP, viewStyle } = useContext(VehicleContext)\r\n const detailLink = getVdpUrl(vehicleData.vehicle.InstanceID)\r\n return (\r\n \r\n {isVDP ? (\r\n {vehicleData.vehicle.Title}\r\n ) : (\r\n {\r\n setCustomClick(vehicleData.vehicle.Title, {\r\n usePageName: true\r\n })\r\n sessionStorage.setItem(SessionStorageKey.VIEW_VEHICLE_LIST, viewStyle.toString())\r\n }}\r\n to={detailLink}\r\n >\r\n {vehicleData.vehicle.Title}\r\n \r\n )}\r\n \r\n \r\n )\r\n}\r\n","import { CSRF_HEADER, CSRF_TOKEN } from './constants'\r\n\r\ninterface IRequestInit extends RequestInit {\r\n body?: T | any\r\n type?: 'json' | 'blob' | 'form-data'\r\n}\r\n\r\nexport const apiRootPath = '/api/v1'\r\n\r\n/**\r\n * Fetching a resource from the network\r\n * @param url\r\n * @param input\r\n * @param timeout - Set timeout for fetch() function, in miliseconds. No timeout will be set if timeout value is null, undefined or 0.\r\n * @returns A promise of type T.\r\n */\r\nexport const fetchAsync = async (url: string, input?: IRequestInit, timeout?: number): Promise => {\r\n let { body, type = 'json', headers } = input || {}\r\n let response: Response\r\n // Construct headers\r\n headers = { ...headers, [CSRF_HEADER]: localStorage.getItem(CSRF_TOKEN) }\r\n\r\n if (type === 'json') {\r\n headers = {\r\n ...headers,\r\n 'Content-Type': 'application/json'\r\n }\r\n }\r\n if (type === 'form-data') {\r\n headers = {\r\n ...headers,\r\n 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'\r\n }\r\n }\r\n\r\n // Construct body\r\n if (body && type === 'json') {\r\n body = JSON.stringify(body)\r\n }\r\n\r\n // Handle timeout\r\n if (timeout) {\r\n const abortController = new AbortController()\r\n\r\n const timer = setTimeout(() => abortController.abort(), timeout)\r\n\r\n try {\r\n response = await fetch(url, { ...input, body, headers, signal: abortController.signal })\r\n } catch (error) {\r\n throw error\r\n } finally {\r\n clearTimeout(timer)\r\n }\r\n } else {\r\n response = await fetch(url, { ...input, body, headers })\r\n }\r\n\r\n // Handle session expired\r\n if (response.status === 401 && window.location.pathname.toUpperCase() !== '/LOGIN') {\r\n window.location.href = '/login?returnUrl=' + encodeURIComponent(window.location.pathname) + '&errorCode=401'\r\n return\r\n }\r\n\r\n // Determine return type\r\n let result: T\r\n const contentType = response.headers.get('content-type')\r\n if (/application\\/json/.test(contentType)) {\r\n result = (await response.json()) as T\r\n } else if (type === 'blob') {\r\n result = {\r\n ...response,\r\n body: await response.blob()\r\n } as any\r\n } else {\r\n result = {\r\n ...response,\r\n body: await response.text()\r\n } as any\r\n }\r\n\r\n if (!response.ok) {\r\n throw result\r\n }\r\n\r\n return result\r\n}\r\n\r\nexport const postAsync = async (\r\n url: string,\r\n input?: IRequestInit,\r\n timeout?: number\r\n): Promise => {\r\n return fetchAsync(url, { ...input, method: 'POST' }, timeout)\r\n}\r\n","import { zIndex } from 'common/constants'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\ninterface IStyledDataTableProps {\r\n maxHeight?: number\r\n striped?: boolean\r\n}\r\n\r\nexport const StyledDataTable = styled.div`\r\n .table-container {\r\n max-height: ${({ maxHeight }) => `${maxHeight}px`};\r\n }\r\n .table {\r\n color: ${({ theme }) => theme.colors.InfinitiFooterFontColor};\r\n border-collapse: separate;\r\n border-spacing: 0;\r\n }\r\n ${({ striped, theme }) =>\r\n striped &&\r\n `tr.table-row:nth-child(odd) {\r\n background: ${theme.colors.tableStriped};\r\n }\r\n tr.table-row:nth-child(even) {\r\n background-color: ${theme.colors.inputBackgroundColor};\r\n }`}\r\n @media (max-width: ${gridBreakPoints.lg}) {\r\n overflow: auto;\r\n scrollbar-width: thin;\r\n }\r\n`\r\nexport const DataTableHeader = styled.div`\r\n padding-top: 8px;\r\n padding-bottom: 5px;\r\n padding-left: 2px;\r\n padding-right: 2px;\r\n`\r\n\r\nexport const DataTableCell = styled.div`\r\n padding-top: 4px;\r\n padding-bottom: 4px;\r\n padding-left: 2px;\r\n padding-right: 2px;\r\n position: relative;\r\n @media (min-width: ${gridBreakPoints.xxl}) {\r\n font-size: 13px;\r\n }\r\n`\r\n","import { useMemo } from 'react'\r\nimport { DataTableCell, DataTableHeader, StyledDataTable } from './DataTable.styled'\r\nimport classNames from 'classnames'\r\nimport { Column, Row, useFilters, useTable } from 'react-table'\r\n\r\nexport interface IDataTableProps {\r\n rowClass?: (row: Row, index?: number) => string\r\n height?: number\r\n columns: ColumnWrapper[]\r\n data: T[]\r\n className?: string\r\n striped?: boolean\r\n emptyText?: string\r\n showNoData?: number\r\n}\r\n\r\nexport const DEFAULT_VISIBLE_ROWS = 10\r\nexport const HEADER_HEIGHT = 39\r\nexport const ROW_HEIGHT = 36.5\r\nexport const DEFAULT_TABLE_HEIGHT = DEFAULT_VISIBLE_ROWS * ROW_HEIGHT + HEADER_HEIGHT\r\n\r\ntype ColumnWrapper = Column & { visible?: boolean }\r\n\r\nexport function DataTable({\r\n columns,\r\n data,\r\n striped = true,\r\n height,\r\n emptyText,\r\n showNoData = data?.length,\r\n rowClass\r\n}: IDataTableProps) {\r\n // Use the state and functions returned from useTable to build your UI\r\n const filteredColumns = useMemo(() => (columns || []).filter((c) => c.visible === undefined || c.visible), [columns])\r\n const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(\r\n {\r\n columns: filteredColumns,\r\n data\r\n },\r\n useFilters\r\n )\r\n\r\n // Render the UI for your table\r\n return (\r\n <>\r\n {!!showNoData && (\r\n \r\n \r\n
\r\n \r\n {headerGroups.map((headerGroup) => (\r\n \r\n {headerGroup.headers.map((column) => (\r\n \r\n {column.render('Header')}\r\n | \r\n ))}\r\n
\r\n ))}\r\n \r\n \r\n {rows.map((row, i) => {\r\n prepareRow(row)\r\n return (\r\n \r\n {row.cells.map((cell) => {\r\n return (\r\n \r\n {cell.render('Cell')}\r\n | \r\n )\r\n })}\r\n
\r\n )\r\n })}\r\n \r\n
\r\n
\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { SessionStorageKey } from 'common/constants'\r\nimport { srpFilters } from 'common/srpFilters'\r\nimport { getSystemSetting, isSystemSettingsEnabled, SystemSettingsCode } from 'common/systemSettingsCode'\r\nimport { IAuctionInfo } from 'types/auctionTypes'\r\nimport { SortOrder } from 'types/baseTypes'\r\nimport { IDtmSearchParams, IListingModel, ISearchData, QueryCriteria, VehicleList } from 'types/dtmTypes'\r\nimport { ISearchFilterResult, IVehicleInfo } from 'types/vehicleTypes'\r\n\r\nexport const AnalyticsStorageKey = {\r\n LOAD_START_TIME: 'LOAD_START_TIME',\r\n USER_LOCATION: 'UserLocation',\r\n GEO_LOCATION: 'GeoLocationValue',\r\n CUSTOM_CLICK_NAME: 'customClickName',\r\n MOBILE_HEADER: 'MobileHeaderValue'\r\n}\r\n\r\nexport const DtmPageName = {\r\n Dashboard: 'My Dashboard',\r\n SRP: 'Search Results Page',\r\n News: 'News',\r\n AdvancedSearch: 'Advanced Search',\r\n SavedSearch: 'Saved Search',\r\n WatchList: 'Watch list',\r\n CurrentBids: 'Current Bids',\r\n VDP: 'Vehicle Detail Page',\r\n PurchaseConfirmation: 'Purchase intent confirmation',\r\n BidHistory: 'Bid History',\r\n VehicleRetail: 'Vehicle Retail Page',\r\n PurchaseHistory: 'Purchase History',\r\n ContactUs: 'Contact Us',\r\n MyProfile: 'My Profile',\r\n AccountSettings: 'Account Settings',\r\n Grounding: 'Grounding'\r\n}\r\n\r\nexport const DtmComponentName = {\r\n VDPDetails: 'VDP Vehicle Details',\r\n VDPVehicleHistory: 'VDP Vehicle History',\r\n VDPBuildData: 'VDP Build Data',\r\n VDPTires: 'VDP Tires and Wheels',\r\n VDPSellerDisclaimer: 'VDP Seller Disclaimer',\r\n VDPDamageSummary: 'VDP Damage Summary',\r\n DashboardInventory: 'My Dashboard Inventory View',\r\n DashboardWatchList: 'My Dashboard Watchlist',\r\n DashboardCurrentBids: 'My Dashboard Current Bids'\r\n}\r\n\r\nexport const DtmPageDetails = {\r\n VDP: 'VDP',\r\n SRP: 'SRP'\r\n}\r\n\r\nexport const DtmPageRollup = {\r\n HomePage: 'HomePage'\r\n}\r\n\r\nexport const enum CustomClickNames {\r\n AvailableInventory = 'Available Inventory'\r\n}\r\n\r\nexport const getPageDetails = (pathName: string, pageName: string) => {\r\n let parent = ''\r\n switch (pageName) {\r\n case DtmPageName.VDP:\r\n case DtmPageName.VehicleRetail:\r\n break\r\n\r\n default:\r\n switch (pathName?.toLowerCase()) {\r\n case '/vehicles':\r\n parent = 'Buy A Vehicle'\r\n break\r\n case '/':\r\n parent = 'Dashboard'\r\n break\r\n case '/contactus':\r\n parent = 'My Account'\r\n break\r\n }\r\n break\r\n }\r\n\r\n let pageDetails = pageName\r\n if (pageName === DtmPageName.SRP) {\r\n pageDetails = DtmPageDetails.SRP\r\n } else if (pageName === DtmPageName.VDP) {\r\n pageDetails = DtmPageDetails.VDP\r\n }\r\n\r\n const parts = [parent, pageDetails].filter((item) => Boolean(item))\r\n return parts.join(' - ')\r\n}\r\n\r\nexport const getPageRollup = (pageName: string): string => {\r\n switch (pageName) {\r\n case DtmPageName.Dashboard:\r\n case DtmPageName.News:\r\n return DtmPageRollup.HomePage\r\n\r\n default:\r\n return pageName\r\n }\r\n}\r\n\r\nexport const getTabName = (pageName: string): string => {\r\n const customClickName = sessionStorage.getItem(AnalyticsStorageKey.CUSTOM_CLICK_NAME)\r\n switch (pageName) {\r\n case DtmPageName.ContactUs:\r\n return `My Account: ${pageName}`\r\n case DtmPageName.Dashboard:\r\n return customClickName == null ? 'Dashboard: Landing Page' : 'Dashboard: My Dashboard'\r\n default:\r\n return pageName\r\n }\r\n}\r\n\r\nexport const getApplicationRevisionId = () => {\r\n var userAgent = navigator.userAgent || navigator.vendor\r\n var device = 'web'\r\n if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {\r\n device = 'iOS'\r\n } else if (userAgent.match(/Android/i)) {\r\n device = 'Android'\r\n }\r\n return device + ':' + navigator.appVersion\r\n}\r\n\r\ninterface ICustomClickOptions {\r\n usePageName?: boolean\r\n}\r\n\r\nexport const setCustomClick = (customClickName: string, { usePageName }: ICustomClickOptions = {}) => {\r\n if (usePageName) {\r\n const { pageName } = AnalyticsStore\r\n customClickName = `${pageName}: ${customClickName}`\r\n }\r\n\r\n sessionStorage.setItem(AnalyticsStorageKey.CUSTOM_CLICK_NAME, customClickName)\r\n AnalyticsStore.customClickName = customClickName\r\n}\r\n\r\nexport interface IAnalyticsState {\r\n enableDtmAnalytics: boolean\r\n environment: string\r\n customClickName?: string\r\n pageName?: string\r\n pageDetails?: string\r\n pageRollup?: string\r\n tabName?: string\r\n loadStart?: Date\r\n}\r\n\r\nexport const AnalyticsStore: IAnalyticsState = {\r\n enableDtmAnalytics: isSystemSettingsEnabled(SystemSettingsCode.ENABLE_DTM_ANALYTICS_TRACE),\r\n environment: getSystemSetting(SystemSettingsCode.DTM_ANALYTICS_ENVIRONMENT),\r\n customClickName: sessionStorage.getItem(AnalyticsStorageKey.CUSTOM_CLICK_NAME)\r\n}\r\n\r\nif (AnalyticsStore.enableDtmAnalytics) {\r\n getGeoLocation()\r\n}\r\n\r\nexport const setPageInfo = (pageName: string) => {\r\n AnalyticsStore.pageName = pageName\r\n AnalyticsStore.pageDetails = getPageDetails(window.location.pathname, pageName)\r\n AnalyticsStore.pageRollup = getPageRollup(pageName)\r\n AnalyticsStore.tabName = getTabName(pageName)\r\n AnalyticsStore.loadStart = new Date()\r\n}\r\n\r\nconst geolocationErrorMap = {\r\n '1': 'PERMISSION_DENIED',\r\n '2': 'POSITION_UNAVAILABLE',\r\n '3': 'TIMEOUT'\r\n}\r\n\r\nexport function getGeoLocation() {\r\n var options = {\r\n enableHighAccuracy: true,\r\n timeout: 5000,\r\n maximumAge: 0\r\n }\r\n\r\n function success(pos) {\r\n var geoString = {\r\n timestamp: pos['timestamp'],\r\n coords: {\r\n latitude: pos['coords']['latitude'],\r\n longitude: pos['coords']['longitude'],\r\n accuracy: pos['coords']['accuracy'],\r\n altitude: pos['coords']['altitude'],\r\n speed: pos['coords']['speed']\r\n }\r\n }\r\n sessionStorage.setItem(AnalyticsStorageKey.GEO_LOCATION, JSON.stringify(geoString))\r\n\r\n sessionStorage.setItem(\r\n SessionStorageKey.USER_LOCATION,\r\n JSON.stringify({\r\n lat: pos['coords']['latitude'],\r\n long: pos['coords']['longitude']\r\n })\r\n )\r\n }\r\n\r\n function error(err) {\r\n var errorStr = geolocationErrorMap[err.code.toString()] || 'Error'\r\n sessionStorage.setItem(AnalyticsStorageKey.GEO_LOCATION, JSON.stringify({ error: errorStr }))\r\n }\r\n\r\n navigator.geolocation.getCurrentPosition(success, error, options)\r\n}\r\n\r\nexport const getInventoryClickName = (ft?: ISearchFilterResult[]) => {\r\n if (!ft) {\r\n return ''\r\n }\r\n\r\n const modelFilter =\r\n ft.find((item) => item.FieldName === srpFilters.Model)?.ChildrenFilter?.find((item) => item.Selected)?.Value || ''\r\n\r\n const yearFilter =\r\n ft.find((item) => item.FieldName === srpFilters.Year)?.ChildrenFilter?.find((item) => item.Selected)?.Value || ''\r\n\r\n return `:${[modelFilter, yearFilter].filter(Boolean).join(':')}`\r\n}\r\n\r\nexport function getListings(listModel: IListingModel[], siteCode: string, vendorCode: string) {\r\n let listedVehicle: VehicleList[] = []\r\n listModel?.forEach((model) => {\r\n const auctionID = model.auctionInfo?.ID\r\n const vin = model.vehicle?.VIN || model.Vin || model.VIN\r\n\r\n if (auctionID) {\r\n listedVehicle.push({ id: `${siteCode}.${vendorCode}.${auctionID}`, vin: vin })\r\n } else {\r\n listedVehicle.push({ vin: vin })\r\n }\r\n })\r\n return listedVehicle\r\n}\r\n\r\nexport function getSearchParameters(response: ISearchData): IDtmSearchParams {\r\n if (!response) {\r\n return {}\r\n }\r\n\r\n const allCirteria = []\r\n response.filters?.forEach((filterParent) => {\r\n filterParent.ChildrenFilter.forEach((filter) => {\r\n if (filter.Selected) {\r\n allCirteria.push({ [filter.FieldName]: filter.FriendlyValue })\r\n }\r\n })\r\n })\r\n\r\n const query: QueryCriteria = {\r\n allCriteria: allCirteria,\r\n id: '',\r\n resultsCount: `${response.TotalRecords}`,\r\n resultsPerPage: `${response.PageSize}`\r\n }\r\n\r\n const sort = response.sortOptions?.find((item) => item.Value === response.sortBy?.Value)\r\n const sortName = sort?.Name.split(' -')[0]\r\n const sortOrder = sort?.SortOrder === SortOrder.ASC ? 'ASC' : 'DESC'\r\n\r\n return { sortBy: `${sortName}:${sortOrder}`, query }\r\n}\r\n","import { IconProps } from 'icons/IconProps'\r\n\r\nexport const SpinnerIcon = ({ width = '1em', height = '1em', className }: IconProps) => {\r\n return (\r\n \r\n )\r\n}\r\n","import { zIndex } from 'common/constants'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyleLoader = styled.div``\r\n\r\nexport interface IProps {\r\n variant?: string\r\n overlay?: boolean\r\n}\r\n\r\ninterface IStyledLoaderProps {\r\n overlay?: boolean\r\n}\r\n\r\nexport const StyledLoader = styled.div`\r\n ${({ overlay }) =>\r\n overlay &&\r\n ` position: absolute;\r\n left: calc(50% - 1rem);\r\n top: calc(50% - 1rem);\r\n `}\r\n`\r\n\r\nexport const StyledPageLoader = styled.div`\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100vw;\r\n height: 100vh;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n z-index: ${zIndex.loader};\r\n`\r\n\r\nexport interface ISpinnerProps {\r\n size?: string\r\n color?: string\r\n}\r\n\r\nexport const StyleCustomLoader = styled.div`\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n fill: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n\r\n .custom-spinner {\r\n position: relative;\r\n animation: my-custom 1s linear infinite;\r\n }\r\n\r\n @-webkit-keyframes my-custom {\r\n 0% {\r\n -webkit-transform: rotate(0deg);\r\n }\r\n\r\n 100% {\r\n -webkit-transform: rotate(360deg);\r\n }\r\n }\r\n @keyframes my-custom {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n`\r\n","import { assetFolders } from 'common/constants'\r\nimport { SpinnerIcon } from 'images/icon/SpinnerIcon'\r\nimport { PropsWithChildren } from 'react'\r\nimport { Spinner } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IProps, ISpinnerProps, StyleCustomLoader, StyledLoader, StyledPageLoader } from './Loader.styled'\r\n\r\nexport const Loader = ({ children, overlay, variant = 'primary' }: PropsWithChildren) => {\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n return (\r\n \r\n \r\n {children}\r\n \r\n \r\n )\r\n}\r\n\r\nexport const OverlayLoader = () => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport const CustomLoader = ({ size, color }: ISpinnerProps) => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\n","export const AUTH_ERROR = 'Invalid User ID or Password'\r\nexport const AUTH_ERROR_2 = 'The login information is not correct. Please call the Level 1 support desk at 844-266-0437'\r\nexport const FORGOT_LABLE =\r\n 'Please enter the User ID associated to your account and instructions for resetting your password will be sent to you.'\r\nexport const INVALID_USER = 'Invalid User'\r\nexport const RESET_PW =\r\n 'An email was sent to your registered email account containing a link to reset your password. Once you reset your password, you can log in to the system.'\r\nexport const BMW_LOGIN_TITLE = 'WELCOME TO
BMW GROUP DIRECT'\r\nexport const NISSAN_LOGIN_TITLE = 'WELCOME TO
NISSAN'\r\nexport const FORGOT_USER_ID = 'To recover your User ID, please contact Customer Care at: 844-266-0437'\r\nexport const FORBIDDEN_PAGE = 'You are not allowed to access this page'\r\nexport const NO_COMMENT_FROM_API_MESSAGE = 'No Data from API'\r\n","import { IHomeSectionHeaderProps } from 'components/Header/HomeSectionHeader'\r\nimport { LayoutContext } from 'contexts/LayoutContext'\r\nimport { PropsWithChildren, useContext } from 'react'\r\nimport { StyledVehicleStickyBar } from './VehicleStickyBar.styled'\r\n\r\ninterface IVehicleStickyBarProps extends IHomeSectionHeaderProps {}\r\n\r\nexport const VehicleStickyBar = ({ children, ...props }: PropsWithChildren) => {\r\n const { isSticky } = useContext(LayoutContext)\r\n return \r\n}\r\n","import { AppRoutes } from 'common/routes'\r\nimport { Loader } from 'components/Loader'\r\nimport { Link } from 'react-router-dom'\r\nimport { IconSvg } from '@prism/icon'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\n\r\ninterface Iprops {\r\n loading: boolean\r\n count: number\r\n}\r\n\r\nexport const CurrentBidsCount = ({ loading, count }: Iprops) => {\r\n return (\r\n <>\r\n {loading ? (\r\n \r\n ) : (\r\n setCustomClick('Manage Bids', { usePageName: true })}\r\n to={AppRoutes.ManageBids}\r\n >\r\n \r\n \r\n Manage Bids ({count ?? 0})\r\n \r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { AppRoutes } from 'common/routes'\r\nimport { Loader } from 'components/Loader'\r\nimport { Link } from 'react-router-dom'\r\nimport { IconSvg } from '@prism/icon'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\n\r\ninterface Iprops {\r\n loading: boolean\r\n count: number\r\n}\r\n\r\nexport const WatchListCount = ({ loading, count }: Iprops) => {\r\n return (\r\n <>\r\n {loading ? (\r\n \r\n ) : (\r\n setCustomClick('Watch List', { usePageName: true })}\r\n to={AppRoutes.WatchList}\r\n >\r\n \r\n \r\n Watch List ({count ?? 0})\r\n \r\n \r\n )}\r\n >\r\n )\r\n}\r\n","export const FileEarMarkArrowDown = () => {\r\n return (\r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\nimport { StyledSlideOutElement } from './SlideOut.styled'\r\n\r\nexport const StyledSlideOutHeading = styled(StyledSlideOutElement)`\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n .title {\r\n font-size: 2.6rem;\r\n }\r\n .vin {\r\n font-size: 1.8rem;\r\n }\r\n`\r\n","import { StyledSlideOutHeading } from './SlideOutHeading.styled'\r\n\r\ninterface IProps {\r\n vehicleTitle: string\r\n vin: string\r\n}\r\nexport const SlideOutHeading = ({ vehicleTitle, vin }: IProps) => {\r\n return (\r\n \r\n {vehicleTitle}
\r\n {vin}
\r\n \r\n )\r\n}\r\n","import Select from 'components/Select/Select'\r\nimport { ValidationErrorMessage } from 'components/Forms'\r\nimport { useFormikContext } from 'formik'\r\nimport { Alert, Form } from 'react-bootstrap'\r\nimport { IDropdownData, IOption } from 'types/baseTypes'\r\nimport { StyledSlideOutElement } from './SlideOut.styled'\r\n\r\ninterface IProps {\r\n label: string\r\n name: string\r\n options: IOption[]\r\n onChange?: (dropdownValue: any) => void\r\n fallbackValue: any\r\n required?: boolean\r\n disabled?: boolean\r\n alertMessage?: string\r\n}\r\n// eslint-disable-next-line prettier/prettier\r\nexport const SlideOutDropdown = ({\r\n alertMessage,\r\n label,\r\n name,\r\n options,\r\n onChange,\r\n disabled = false,\r\n fallbackValue,\r\n required = false\r\n}: IProps) => {\r\n const formik = useFormikContext()\r\n const selectedValue =\r\n options?.find((option) => option.value === formik?.values?.[name]) ||\r\n options?.find((option) => option.value === fallbackValue)\r\n\r\n return (\r\n \r\n \r\n {label}\r\n \r\n \r\n {alertMessage && (\r\n \r\n {alertMessage}\r\n \r\n )}\r\n\r\n {formik.errors[name] && formik.touched[name] && (\r\n {formik.errors[name]}\r\n )}\r\n \r\n )\r\n}\r\n","import { Form } from 'react-bootstrap'\r\nimport { StyledSlideOutElement } from './SlideOut.styled'\r\n\r\ninterface IProps {\r\n label: string\r\n inputText: string\r\n}\r\nexport const SlideOutReadOnlyInput = ({ label, inputText }: IProps) => {\r\n return (\r\n \r\n \r\n {label}\r\n \r\n \r\n \r\n )\r\n}\r\n","import { Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\nimport { StyledSlideOutElement } from './SlideOut.styled'\r\n\r\nexport const StyledSlideOutBidAmountInput = styled(StyledSlideOutElement)`\r\n display: flex;\r\n flex-direction: column;\r\n width: 80%;\r\n\r\n .dollar {\r\n position: absolute;\r\n transform: translate(110%, 50%);\r\n }\r\n .amount-input {\r\n position: relative;\r\n display: flex;\r\n flex: 1;\r\n }\r\n\r\n // Hide arrow on input type number\r\n /* Chrome, Safari, Edge, Opera */\r\n .currency-input::-webkit-outer-spin-button,\r\n .currency-input::-webkit-inner-spin-button {\r\n -webkit-appearance: none;\r\n margin: 0;\r\n }\r\n\r\n // Hide arrow on input type number\r\n /* Firefox */\r\n .currency-input {\r\n -moz-appearance: textfield;\r\n }\r\n`\r\n\r\nexport const StyledBidAmountButton = styled(Button)`\r\n background: #fff;\r\n border: ${({ theme }) => theme.colors.borderInput};\r\n padding-left: 1.2rem;\r\n padding-right: 1.2rem;\r\n`\r\n","import { useEffect, useState } from 'react'\r\nimport { StyledBidAmountButton, StyledSlideOutBidAmountInput } from './SlideOutBidAmountInput.styled'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons'\r\nimport { Form } from 'react-bootstrap'\r\nimport { useFormikContext } from 'formik'\r\nimport { BidAgainFormValues } from 'types/formikTypes'\r\nimport { BidAmountTypeOptions, EnterKeyCharCode } from 'common/constants'\r\nimport { ValidationErrorMessage } from 'components/Forms'\r\nimport { formatNumber, roundUpToNearest } from 'utils/numberUtils'\r\nimport { parseNumberWithCommas } from 'utils/stringUtils'\r\n\r\ninterface IProps {\r\n bidIncreasement: number\r\n bidIncreasementString: string\r\n nextBidAmountString: string\r\n nextBidAmount: number\r\n disabled?: boolean\r\n}\r\nexport const SlideOutBidAmountInput = ({\r\n bidIncreasement,\r\n bidIncreasementString,\r\n nextBidAmountString,\r\n nextBidAmount,\r\n disabled = false\r\n}: IProps) => {\r\n const formik = useFormikContext()\r\n const [bidAmountText, setBidAmountText] = useState(formatNumber(nextBidAmount))\r\n\r\n function updateBidAmount(bidAmount: number) {\r\n formik?.setFieldValue('BidAmount', bidAmount, false)\r\n setBidAmountText(formatNumber(bidAmount))\r\n }\r\n\r\n const handleBidAmountChange = (bidAmount: number) => {\r\n if (bidAmount > nextBidAmount) {\r\n updateBidAmount(bidAmount)\r\n } else {\r\n // reset to original value\r\n updateBidAmount(nextBidAmount)\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n setBidAmountText(formatNumber(formik?.values.BidAmount))\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [formik?.values.BidAmount])\r\n\r\n return (\r\n \r\n \r\n
setBidAmountText(e.target.value)}\r\n onBlur={(e) => {\r\n const bidAmount = parseNumberWithCommas(e.target.value)\r\n handleBidAmountChange(roundUpToNearest(bidAmount, formik.values.BidAmount, bidIncreasement))\r\n }}\r\n value={bidAmountText}\r\n onKeyPress={(event) => {\r\n if (event.charCode === EnterKeyCharCode) {\r\n const bidAmount = parseNumberWithCommas(bidAmountText)\r\n handleBidAmountChange(roundUpToNearest(bidAmount, formik.values.BidAmount, bidIncreasement))\r\n }\r\n }}\r\n />\r\n\r\n {\r\n handleBidAmountChange(formik.values.BidAmount + bidIncreasement)\r\n }}\r\n >\r\n \r\n \r\n\r\n {\r\n handleBidAmountChange(formik.values.BidAmount - bidIncreasement)\r\n }}\r\n >\r\n \r\n \r\n $\r\n \r\n\r\n {formik.errors.BidAmount && formik.touched.BidAmount && (\r\n {formik.errors.BidAmount}\r\n )}\r\n \r\n {nextBidAmountString} or Higher (Increment {bidIncreasementString})\r\n \r\n \r\n )\r\n}\r\n","import { StyledSlideOutElement } from './SlideOut.styled'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport parse from 'html-react-parser'\r\nimport { HTMLText } from 'components/Share/HtmlText'\r\nimport { Spinner, OverlayTrigger, Popover } from 'react-bootstrap'\r\nimport { IIncentive, IVehicleCharges } from 'types/vehicleTypes'\r\nimport { useRef } from 'react'\r\n\r\ninterface IProps {\r\n feeLoading: boolean // loader for generic buyer premium\r\n buyerFeeString: string\r\n deliveryCharge: number\r\n vehicleCharges: IVehicleCharges[]\r\n isIncentiveAccumulate: boolean\r\n incentives: IIncentive[]\r\n estimatedGrossPrice: number\r\n}\r\n\r\nexport const SlideOutPricingDetails = ({\r\n buyerFeeString,\r\n deliveryCharge,\r\n estimatedGrossPrice,\r\n vehicleCharges,\r\n isIncentiveAccumulate,\r\n incentives,\r\n feeLoading\r\n}: IProps) => {\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n const slideOutElementRef = useRef(null)\r\n return (\r\n \r\n \r\n Total Transaction Charges:\r\n \r\n {feeLoading ? : buyerFeeString || 'N/A'}\r\n \r\n \r\n {getLocalText('VIEW_FEES_TEXT')}\r\n {getLocalText('VIEW_FEES_INFORMATION')}\r\n \r\n }\r\n >\r\n ({getLocalText('VIEW_FEES_TEXT')})\r\n \r\n
\r\n \r\n Total Delivery Charge: {deliveryCharge || 'N/A'}\r\n
\r\n {vehicleCharges?.map((charge, index) => (\r\n \r\n {charge.VehicleChargeTypeDescription}: {charge.PriceString}\r\n
\r\n ))}\r\n {!isIncentiveAccumulate &&\r\n incentives?.map((incentive, index) => (\r\n \r\n {incentive.Name}: {incentive.AmountString}\r\n
\r\n ))}\r\n \r\n Estimated Gross Price: \r\n {isNaN(estimatedGrossPrice) ? (\r\n 'N/A'\r\n ) : feeLoading ? (\r\n \r\n ) : (\r\n '$' + new Intl.NumberFormat().format(estimatedGrossPrice)\r\n )}\r\n
\r\n \r\n \r\n )\r\n}\r\n","import { getBaseVehicle, getDetailedDeliveryInfo, getGenericPremium } from 'apis/vehicleApis'\r\nimport { BidAmountTypeOptions, SelfArrangedTransportProviderId } from 'common/constants'\r\nimport { SlideOutHeading } from 'components/SlideOut/SlideOutHeading'\r\nimport { SlideOutDropdown } from 'components/SlideOut/SlideOutDropdown'\r\nimport { SlideOutReadOnlyInput } from 'components/SlideOut/SlideOutReadOnlyInput'\r\nimport { useState, useMemo, useEffect, useCallback } from 'react'\r\nimport { useBiddingSidePanel } from 'store/useBiddingSidePanelStore'\r\nimport { IOption, IDropdownData } from 'types/baseTypes'\r\nimport { DeliveryInformation, GetBaseVehicleRequest, IDeliveryQuote, IVehicleFeeRequest } from 'types/vehicleTypes'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledSlideOutElement } from 'components/SlideOut/SlideOut.styled'\r\nimport { SlideOutBidAmountInput } from 'components/SlideOut/SlideOutBidAmountInput'\r\nimport { StyledSlideOutBidAmountInput } from 'components/SlideOut/SlideOutBidAmountInput.styled'\r\nimport { Form } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { SlideOutPricingDetails } from 'components/SlideOut/SlideOutPricingDetails'\r\nimport { useFormikContext } from 'formik'\r\nimport { BidAgainFormValues } from 'types/formikTypes'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { debounce } from 'lodash'\r\nimport { useSidePanelRealTimeUpdateDealer } from 'hooks/useSidePanelRealTimeUpdateDealer'\r\nimport { IAccountInfo } from 'types/accountTypes'\r\n\r\ninterface IBiddingSidePanelFormProps {\r\n isDealerShipSelectable: boolean\r\n setFetchLoading: (loading: boolean) => void\r\n}\r\nexport const BiddingSidePanelFormContent: React.FC = ({\r\n isDealerShipSelectable,\r\n setFetchLoading\r\n}) => {\r\n const formik = useFormikContext()\r\n const [biddingVehicleInstanceId] = useBiddingSidePanel((state) => [state.biddingVehicleInstanceId], shallow)\r\n const biddingVehicle = useVehicleStore((state) =>\r\n state.vehicles?.find((vehicleData) => vehicleData.vehicle.InstanceID === biddingVehicleInstanceId)\r\n )\r\n\r\n const { AssociatedBuyers, CurrentBuyerID } = useGlobalStore((state) => state.userClaims)\r\n\r\n const [feeLoading, setFeeLoading] = useState(false)\r\n const [buyerFee, setBuyerFee] = useState(0)\r\n const [buyerFeeString, setBuyerFeeString] = useState('N/A')\r\n const [hasAnyChargeRange, setHasAnyChargeRange] = useState(false)\r\n const [deliveryInformation, setDeliveryInformation] = useState(null)\r\n const [vehicleInfo, setVehicleInfo] = useState(biddingVehicle?.vehicle)\r\n\r\n const dealershipOptions: IOption[] = useMemo(\r\n () =>\r\n AssociatedBuyers.filter((dealership) =>\r\n biddingVehicle?.auctionInfo.SalesSessionStepBuyerTypeIds.some(\r\n (sessionStepBuyerType) => sessionStepBuyerType === dealership.BuyerTypeID\r\n )\r\n ).map((dealership) => ({\r\n item: dealership,\r\n label: dealership.Description,\r\n value: dealership.ID\r\n })),\r\n\r\n [AssociatedBuyers, biddingVehicle?.auctionInfo.SalesSessionStepBuyerTypeIds]\r\n )\r\n\r\n const buyerAccountOptions: IOption[] = useMemo(\r\n () =>\r\n deliveryInformation?.CurrentBuyerAlternateIdentifiers?.map((acc: IAccountInfo) => ({\r\n item: acc,\r\n label: acc.Description,\r\n value: acc.Description\r\n })),\r\n [deliveryInformation?.CurrentBuyerAlternateIdentifiers]\r\n )\r\n\r\n const paymentTypes: IOption[] = useMemo(() => {\r\n return deliveryInformation?.PaymentTypes?.map((paymentType) => ({\r\n item: paymentType,\r\n label: paymentType.Description,\r\n value: paymentType.ID\r\n }))\r\n }, [deliveryInformation?.PaymentTypes])\r\n\r\n const selfArrangeTransportationProvider: IDropdownData = useMemo(\r\n () => deliveryInformation?.TransportProviders.find((provider) => provider.ID === SelfArrangedTransportProviderId),\r\n [deliveryInformation?.TransportProviders]\r\n )\r\n\r\n const estimatedGrossPrice = useMemo(() => {\r\n if (!biddingVehicle?.auctionInfo) {\r\n return undefined\r\n }\r\n\r\n const totalCharges =\r\n vehicleInfo?.Charges?.reduce((accumulator, currentValue) => accumulator + currentValue.Price, 0) || 0\r\n\r\n const promotions =\r\n vehicleInfo?.Incentives?.reduce((accumulator, currentValue) => accumulator + currentValue.Amount, 0) || 0\r\n\r\n let total = 0\r\n const deliveryPrice = deliveryInformation?.QuotePrice || 0 // for now this almost always 0 because we default to self-arranged\r\n\r\n // for now this fee only applicable for Nissan\r\n const titleOptionFee = deliveryInformation?.TitleDeliveryCharge || 0\r\n const nextBidAmount = biddingVehicle.auctionInfo.NextBidAmount\r\n if (vehicleInfo?.IsIncentiveAccumulate) {\r\n total = buyerFee + nextBidAmount + deliveryPrice + titleOptionFee + totalCharges\r\n } else {\r\n total = buyerFee + nextBidAmount + deliveryPrice + titleOptionFee + totalCharges + promotions\r\n }\r\n return total\r\n }, [\r\n biddingVehicle.auctionInfo,\r\n buyerFee,\r\n deliveryInformation?.QuotePrice,\r\n deliveryInformation?.TitleDeliveryCharge,\r\n vehicleInfo?.Charges,\r\n vehicleInfo?.Incentives,\r\n vehicleInfo?.IsIncentiveAccumulate\r\n ])\r\n\r\n const fetchDetailedDeliveryInfo = useCallback(\r\n async (biddingDealerID?: number) => {\r\n if (biddingVehicle?.vehicle && biddingVehicle?.auctionInfo) {\r\n const vehicle = biddingVehicle.vehicle\r\n\r\n const salePrice = biddingVehicle.auctionInfo.NextBidAmount || vehicle.FinalPrice\r\n\r\n const deliveryQuote: IDeliveryQuote = {\r\n ChannelID: vehicle.SaleChannelID,\r\n InterestID: vehicle.OfferID,\r\n InterestStatusID: vehicle.OfferStatusID,\r\n LocationID: vehicle.LocationID,\r\n PaymentTypeID: 0,\r\n SalePrice: salePrice,\r\n SalesSessionStepId: vehicle.SalesSessionStepID,\r\n VehicleInstanceID: vehicle.InstanceID\r\n }\r\n const deliveryInformation = await getDetailedDeliveryInfo(\r\n deliveryQuote,\r\n biddingDealerID || biddingVehicle.auctionInfo.BuyerID\r\n )\r\n\r\n formik.setFieldValue('PaymentTypeID', deliveryInformation.PaymentTypeID, false)\r\n formik.setFieldValue('BuyerAccountReference', deliveryInformation.CurrentBuyerAccountRef, false)\r\n setDeliveryInformation(deliveryInformation)\r\n setBuyerFee(deliveryInformation.BuyerFee)\r\n setBuyerFeeString(deliveryInformation.BuyerFeeString)\r\n setHasAnyChargeRange(deliveryInformation.HasAnyChargeRange)\r\n }\r\n },\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [biddingVehicle?.auctionInfo, biddingVehicle?.vehicle]\r\n )\r\n\r\n const fetchVehicleInformation = async (biddingDealerID?: number) => {\r\n const payload = new GetBaseVehicleRequest([biddingVehicle])\r\n payload.IncludeAuctionData = true\r\n payload.IncludeBaseData = true\r\n payload.IncludeInspectionReport = false\r\n const {\r\n Items: [vehicleData]\r\n } = await getBaseVehicle(payload, biddingDealerID)\r\n setVehicleInfo(vehicleData.vehicle)\r\n }\r\n const handleDealerChange = async (dealershipId?: number) => {\r\n dealershipId = dealershipId || biddingVehicle.auctionInfo.BuyerID\r\n try {\r\n setFetchLoading(true)\r\n await Promise.all([fetchVehicleInformation(dealershipId), fetchDetailedDeliveryInfo(dealershipId)])\r\n } catch (error) {\r\n } finally {\r\n setFetchLoading(false)\r\n }\r\n }\r\n useSidePanelRealTimeUpdateDealer(formik, handleDealerChange)\r\n\r\n const requestGenericPremiumOnBidMountChange = debounce(async (bidAmount: number, biddingDealerId: number) => {\r\n if (hasAnyChargeRange) {\r\n try {\r\n const feeRequest: IVehicleFeeRequest = {\r\n VehicleInstanceId: biddingVehicle?.vehicle.InstanceID,\r\n LocationId: biddingVehicle?.vehicle.LocationID,\r\n SaleChannelId: biddingVehicle?.vehicle.SaleChannelID,\r\n Price: bidAmount\r\n }\r\n setFeeLoading(true)\r\n const feeResponse = await getGenericPremium(feeRequest, biddingDealerId)\r\n\r\n setHasAnyChargeRange(feeResponse.HasAnyChargeRange)\r\n setBuyerFee(feeResponse.Premium)\r\n setBuyerFeeString(feeResponse.PremiumString)\r\n } catch (error) {\r\n console.error(error)\r\n } finally {\r\n setFeeLoading(false)\r\n }\r\n }\r\n }, 300)\r\n\r\n useEffect(() => {\r\n requestGenericPremiumOnBidMountChange(formik.values.BidAmount, formik.values?.BiddingDealerID)\r\n }, [formik.values.BidAmount, formik.values?.BiddingDealerID])\r\n\r\n return (\r\n <>\r\n \r\n \r\n\r\n \r\n\r\n {deliveryInformation?.CurrentBuyerAlternateIdentifiers?.length > 1 && (\r\n account.Description === deliveryInformation?.CurrentBuyerAccountRef\r\n )?.Description\r\n }\r\n name=\"BuyerAccountReference\"\r\n >\r\n )}\r\n\r\n \r\n\r\n {/* bid again */}\r\n {biddingVehicle?.auctionInfo?.HasPreviousBid ? (\r\n <>\r\n \r\n formik.setFieldValue('BidAmountType', event.target.value)}\r\n />\r\n \r\n \r\n\r\n \r\n formik.setFieldValue('BidAmountType', event.target.value)}\r\n />\r\n\r\n \r\n \r\n >\r\n ) : (\r\n // first bid\r\n \r\n \r\n Enter Bid Amount\r\n \r\n \r\n \r\n )}\r\n\r\n \r\n >\r\n )\r\n}\r\n","import { BidAgainFormValues } from './../types/formikTypes'\r\nimport { useEffect } from 'react'\r\nimport { FormikHelpers } from 'formik'\r\nimport { useBiddingSidePanel } from 'store/useBiddingSidePanelStore'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\n\r\n// when dealership changed by dealership dropdown manage bids page\r\n// we want all clients of that user (eg: watchlist side panel, other tabs of manage bid) follow the updated BiddingDealerID\r\n// this hook also activate when we open side panel\r\nexport const useSidePanelRealTimeUpdateDealer = (\r\n formikHelper: FormikHelpers,\r\n dealershipUpdatedCallback: () => void\r\n) => {\r\n const biddingVehicleInstanceId = useBiddingSidePanel((state) => state.biddingVehicleInstanceId)\r\n const biddingVehicle = useVehicleStore((state) =>\r\n state.vehicles?.find((vehicleData) => vehicleData.vehicle.InstanceID === biddingVehicleInstanceId)\r\n )\r\n useEffect(() => {\r\n formikHelper.setFieldValue('BiddingDealerID', biddingVehicle?.auctionInfo.BuyerID, false)\r\n formikHelper.setFieldValue('BidAmount', biddingVehicle?.auctionInfo.NextBidAmount, false)\r\n\r\n // fetchDetailedDeliveryInfo()\r\n dealershipUpdatedCallback()\r\n\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [biddingVehicle?.auctionInfo.BuyerID])\r\n}\r\n","import { Button, Spinner } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledSpinnerButton = styled(Button)`\r\n .spinner-border {\r\n margin-left: 5px;\r\n width: 1em;\r\n height: 1em;\r\n }\r\n`\r\n","import { ComponentProps, PropsWithChildren } from 'react'\r\nimport { Button as ReactBootStrapButton } from 'react-bootstrap'\r\nimport Spinner from 'react-bootstrap/Spinner'\r\nimport { StyledSpinnerButton } from './SpinnerButton.styled'\r\n\r\nexport interface IButtonProps extends ComponentProps {\r\n isLoading: boolean\r\n}\r\n\r\nexport const SpinnerButton = ({ isLoading, disabled, children, ...props }: PropsWithChildren) => {\r\n return (\r\n \r\n {children}\r\n {isLoading && }\r\n \r\n )\r\n}\r\nexport default SpinnerButton\r\n","import { ComponentProps, useEffect, useState } from 'react'\r\nimport { Alert } from 'react-bootstrap'\r\n\r\nconst DEFAULT_DISMISSABLE_TIMEOUT = 3000\r\ninterface IProps extends ComponentProps {\r\n message: string\r\n variant?: 'danger' | 'success'\r\n autoDismissable?: boolean | number\r\n onClose?: () => void\r\n}\r\nexport const DismissableAlert = ({ message, variant = 'danger', onClose, autoDismissable, ...props }: IProps) => {\r\n const [show, setShow] = useState(!!message)\r\n\r\n useEffect(() => {\r\n setShow(Boolean(message))\r\n }, [message])\r\n\r\n useEffect(() => {\r\n let timeoutHandler\r\n if (autoDismissable && show) {\r\n const timeout = typeof autoDismissable === 'number' ? autoDismissable : DEFAULT_DISMISSABLE_TIMEOUT\r\n\r\n timeoutHandler = setTimeout(() => {\r\n setShow(false)\r\n onClose?.()\r\n }, timeout)\r\n }\r\n\r\n return () => {\r\n if (timeoutHandler) {\r\n clearTimeout(timeoutHandler)\r\n }\r\n }\r\n }, [autoDismissable, show])\r\n\r\n return (\r\n show && (\r\n {\r\n setShow(false)\r\n onClose?.()\r\n }}\r\n dismissible\r\n {...props}\r\n >\r\n {message}\r\n \r\n )\r\n )\r\n}\r\n","import { bidOnVehicle } from 'apis/vehicleApis'\r\nimport { BidAmountTypeOptions, BuyItNowPrice, SelfArrangedTransportProviderId, VehicleStatuses } from 'common/constants'\r\nimport { SlideOut } from 'components/SlideOut/SlideOut'\r\nimport { useEffect, useState } from 'react'\r\nimport { useBiddingSidePanel } from 'store/useBiddingSidePanelStore'\r\nimport { IBidOnVehicleRequest } from 'types/vehicleTypes'\r\nimport shallow from 'zustand/shallow'\r\nimport { Formik, FormikHelpers } from 'formik'\r\nimport { BidAgainFormValues } from 'types/formikTypes'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { number, object, ObjectSchema, string } from 'yup'\r\nimport { useSignalRStore } from 'store/useSignalRStore'\r\nimport { BiddingSidePanelFormContent } from './BiddingSidePanelFormContent'\r\nimport { Alert, Button, Form } from 'react-bootstrap'\r\nimport SpinnerButton from 'components/Buttons/SpinnerButton'\r\nimport { StyledSlideOutElement } from 'components/SlideOut/SlideOut.styled'\r\nimport { DismissableAlert } from 'components/DismissableAlert/DismissableAlert'\r\nimport { CountDownWithColor } from 'modules/BuyerActivity/CountDownWithColor'\r\nimport { useCountdown } from 'hooks/useCountdown'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useLocation } from 'react-router-dom'\r\n\r\nconst bidAgainValidationSchema: ObjectSchema = object({\r\n VehicleInstanceId: number().required().positive().integer(),\r\n BidAmount: number().required('Required').positive('Required').integer(),\r\n PaymentTypeID: number().required().positive('Required').integer(),\r\n BiddingDealerID: number().required().positive().integer(),\r\n BidAmountType: string()\r\n .required()\r\n .oneOf(['CurrentBidAmount', 'UpdateBidAmount'] as const),\r\n TransportCompanyID: number().required().positive().integer(),\r\n BuyerAccountReference: string()\r\n})\r\ninterface IBiddingSidePanelProps {\r\n isDealerShipSelectable: boolean\r\n}\r\nexport const BiddingSidePanel: React.FC = ({ isDealerShipSelectable }) => {\r\n const updateVehicleAuction = useVehicleStore((state) => state.updateVehicleAuction)\r\n const [isOpen, biddingVehicleInstanceId, setBiddingVehicleInstaceId] = useBiddingSidePanel(\r\n (state) => [state.isOpen, state.biddingVehicleInstanceId, state.setBiddingVehicleInstanceId],\r\n shallow\r\n )\r\n const biddingVehicle = useVehicleStore((state) =>\r\n state.vehicles?.find((vehicleData) => vehicleData.vehicle.InstanceID === biddingVehicleInstanceId)\r\n )\r\n\r\n const { userInteraction } = useDtmAnalytics()\r\n const location = useLocation()\r\n useEffect(() => {\r\n setBiddingVehicleInstaceId(null)\r\n }, [location.pathname])\r\n\r\n const connectionID = useSignalRStore((state) => state.connectionID)\r\n const [isBidSuccess, setIsBidSuccess] = useState(false)\r\n const [bidResponseMessage, setBidResponseMessage] = useState('')\r\n const [loading, setLoading] = useState(false)\r\n const { seconds: timeOut } = useCountdown(biddingVehicle?.auctionInfo?.EndDate)\r\n const showBidButton =\r\n biddingVehicle?.auctionInfo?.CanBid && timeOut > 0 && biddingVehicle?.vehicle?.StatusID === VehicleStatuses.OnSale\r\n\r\n const biddingHandler = async (values: BidAgainFormValues, formikHelpers: FormikHelpers) => {\r\n if (!biddingVehicle) return\r\n\r\n const bidRequest: IBidOnVehicleRequest = {\r\n VehicleInstanceId: values.VehicleInstanceId,\r\n BidAmount:\r\n values.BidAmountType === BidAmountTypeOptions.CurrentBidAmount\r\n ? biddingVehicle?.auctionInfo.UserMaxBid\r\n : +values.BidAmount,\r\n BuyItNowPrice: BuyItNowPrice,\r\n QuickBid: false,\r\n ConnectionId: connectionID,\r\n ReferenceNumber: values.BuyerAccountReference,\r\n SalesSessionStepId: biddingVehicle.vehicle.SalesSessionStepID,\r\n DeliveryQuote: {\r\n PaymentTypeID: values.PaymentTypeID,\r\n TransportCompanyID: values.TransportCompanyID,\r\n ChannelID: biddingVehicle.vehicle.SaleChannelID,\r\n SalePrice: values.BidAmount || biddingVehicle.vehicle.FinalPrice,\r\n SalesSessionStepId: biddingVehicle.vehicle.SalesSessionStepID,\r\n VehicleInstanceID: biddingVehicle.vehicle.InstanceID\r\n }\r\n }\r\n\r\n try {\r\n setLoading(true)\r\n const vehicleDataResponse = await bidOnVehicle(bidRequest, values.BiddingDealerID)\r\n\r\n // update auctionInfo from response\r\n if (vehicleDataResponse.Items?.[0]?.auctionInfo) {\r\n formikHelpers.setFieldValue('BidAmount', vehicleDataResponse.Items[0].auctionInfo.NextBidAmount)\r\n updateVehicleAuction({\r\n auctionInfo: vehicleDataResponse.Items[0].auctionInfo,\r\n vehicleInstanceID: vehicleDataResponse.Items[0].vehicle.InstanceID\r\n })\r\n }\r\n\r\n if (bidRequest.ReferenceNumber) {\r\n formikHelpers.setFieldValue('BuyerAccountReference', bidRequest.ReferenceNumber)\r\n }\r\n\r\n // show response message\r\n setBidResponseMessage(\r\n vehicleDataResponse.Items?.[0]?.auctionInfo.ResponseMessage || vehicleDataResponse.ErrorMessages[0]\r\n )\r\n setIsBidSuccess(vehicleDataResponse.Success)\r\n } catch (error) {\r\n console.error(error)\r\n } finally {\r\n setLoading(false)\r\n }\r\n //analytics\r\n userInteraction(`${window.webData.pageName} : Place Bid`, [\r\n { auctionInfo: biddingVehicle.auctionInfo, VIN: biddingVehicle.vehicle.VIN }\r\n ])\r\n }\r\n\r\n const resetSidePanel = () => {\r\n setBiddingVehicleInstaceId(null)\r\n setBidResponseMessage('')\r\n }\r\n\r\n if (!isOpen()) return null\r\n return (\r\n {\r\n resetSidePanel()\r\n }}\r\n >\r\n \r\n {(props) => (\r\n \r\n )}\r\n \r\n \r\n )\r\n}\r\n","import { Popover } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const AttachFilePopoverStyled = styled(Popover)`\r\n box-shadow: 0 0.2rem 0.5rem rgb(0 0 0 / 25%);\r\n\r\n .popover-body {\r\n margin-top: 0.5rem;\r\n font-size: 1.4rem;\r\n padding: 1rem;\r\n }\r\n &.popover {\r\n min-width: 20%;\r\n max-width: 30%;\r\n }\r\n .popover-header {\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n color: #fff;\r\n font-size: 1.6rem;\r\n }\r\n .arrow {\r\n display: none;\r\n }\r\n\r\n .popover-header::before {\r\n display: none;\r\n }\r\n\r\n .download-link {\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n cursor: pointer;\r\n font-size: 1.6rem;\r\n }\r\n\r\n .attachments-list {\r\n padding-top: 1rem;\r\n .attachment-item {\r\n display: block;\r\n padding-bottom: 0.3rem;\r\n margin-top: 0.5rem;\r\n }\r\n }\r\n`\r\n","import { faFile, faFileImage, faFilePdf, faFileVideo } from '@fortawesome/free-regular-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { getMultipleVehicleDocuments } from 'apis/vehicleApis'\r\nimport { Loader } from 'components/Loader'\r\nimport { forwardRef } from 'react'\r\nimport { Popover, PopoverProps } from 'react-bootstrap'\r\nimport { DocumentFileType } from 'types/baseTypes'\r\n\r\nimport { useFetch } from '../hooks/useFetch'\r\nimport { AttachFilePopoverStyled } from './PopoverAttachment.styled'\r\n\r\ninterface IProps extends Omit {\r\n vehicleInstanceID: number\r\n VIN: string\r\n}\r\n\r\nexport const PopoverAttachment = forwardRef(({ vehicleInstanceID, VIN, ...rest }: IProps, ref) => {\r\n const { loading, data: documents } = useFetch(() => getMultipleVehicleDocuments(vehicleInstanceID))\r\n\r\n return (\r\n \r\n Attached Files\r\n \r\n VIN: {VIN}\r\n {loading && }\r\n {!loading && documents?.length > 0 && (\r\n \r\n {documents.map(({ ID, DocumentDescription, FileName, DocumentURL }) => (\r\n
\r\n
window.open(DocumentURL, \"_parent'\")}>\r\n {!!DocumentDescription && (\r\n \r\n )}{' '}\r\n {FileName}\r\n
\r\n
\r\n ))}\r\n
\r\n )}\r\n \r\n \r\n )\r\n})\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledVDPHistory = styled.div`\r\n font-size: 1.4rem;\r\n color: #494949;\r\n margin-top: 3rem;\r\n\r\n .item {\r\n margin-bottom: 0.4rem;\r\n\r\n > label {\r\n font-weight: 700;\r\n padding-right: 0.3rem;\r\n }\r\n }\r\n`\r\n","import { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IPurchaseHistory } from 'types/accountTypes'\r\nimport { formatDate } from 'utils/dateUtils'\r\nimport { StyledVDPHistory } from './VDPHistory.styled'\r\n\r\ninterface IProps {\r\n vehiclePurchase: IPurchaseHistory\r\n}\r\nexport const VDPHistory = ({ vehiclePurchase }: IProps) => {\r\n const { getLocalText } = useGlobalStore((state) => state)\r\n\r\n return (\r\n <>\r\n {vehiclePurchase && (\r\n \r\n \r\n \r\n {vehiclePurchase.TotalPriceString}\r\n
\r\n \r\n \r\n {vehiclePurchase.PreAdjustmentPriceString}\r\n
\r\n \r\n \r\n {formatDate(vehiclePurchase.PurchaseDate, 'DD t')}\r\n
\r\n \r\n \r\n {vehiclePurchase.InvoiceNumber}\r\n
\r\n \r\n \r\n {vehiclePurchase.PaymentType}\r\n
\r\n \r\n \r\n {vehiclePurchase.Location}\r\n
\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { faPaperclip } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { BidSectionContainer, StyledVehicleBidBuyInformation } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { PopoverAttachment } from 'modules/PopoverAttachment'\r\nimport { VDPHistory } from 'modules/VDP/VDPHistory'\r\nimport { StyledVehicleDetailsBody, StyledVehicleDetailsHeaderRow } from 'modules/VehicleList'\r\nimport { lazy, Suspense, useContext } from 'react'\r\nimport { Col, OverlayTrigger, Row } from 'react-bootstrap'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { IVDPSearchParams } from 'types/ISearchParams'\r\nimport { IVehicleData } from 'types/vehicleTypes'\r\nimport { parseUrlSearchParams } from 'utils/urlParams'\r\n\r\nimport { UserMaxBid } from './UserMaxBid'\r\nimport { VehicleActions } from './VehicleActions'\r\nimport { VehicleBidBuyActions } from './VehicleBidBuyActions'\r\nimport { VehicleBidHistoryLink } from './VehicleBidHistoryLink'\r\nimport { VehicleContext } from './VehicleContext'\r\nimport { PaperClipButton, VehicleVin } from './VehicleDetails.styled'\r\nimport { VehicleNote } from './VehicleNote'\r\nimport { VehiclePriceSection } from './VehiclePriceSection'\r\nimport { VehicleProperties } from './VehicleProperties'\r\nimport { VehicleTags } from './VehicleTags'\r\nimport { VehicleTimer } from './VehicleTimer'\r\nimport { VehicleTitleSection } from './VehicleTitleSection'\r\n\r\nexport interface IProps {\r\n vehicleData: IVehicleData\r\n}\r\nexport const VehicleInformation = ({ vehicleData }: IProps) => {\r\n const location = useLocation()\r\n const isVdpHistory = parseUrlSearchParams(location.search).history === 'true'\r\n const hideBuyOptions = parseUrlSearchParams(location.search).history === 'true'\r\n const { retailView } = useContext(VehicleContext)\r\n\r\n return (\r\n \r\n \r\n <>\r\n \r\n >\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {vehicleData.vehicle.VIN}\r\n {vehicleData.vehicle.HasExternalAttachments && !isVdpHistory && (\r\n (\r\n \r\n )}\r\n >\r\n \r\n \r\n \r\n \r\n )}\r\n \r\n \r\n \r\n \r\n {hideBuyOptions && vehicleData.PurchaseHistory ? (\r\n \r\n \r\n \r\n ) : (\r\n <>\r\n {!retailView && (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n )}\r\n >\r\n )}\r\n
\r\n \r\n )\r\n}\r\n","import { Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\nimport { zIndex } from 'common/constants'\r\n\r\ninterface IShowProps {\r\n show: boolean\r\n}\r\nexport const StyledScrollButton = styled(Button)`\r\n position: fixed;\r\n bottom: 7rem;\r\n right: 5rem;\r\n width: 4rem;\r\n height: 4rem;\r\n border-radius: 50%;\r\n background-color: #fff;\r\n border: 0.1rem solid #ccc;\r\n box-shadow: 0 0 0.5rem 0.2rem rgb(0 0 0 / 10%);\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-size: 1rem;\r\n font-weight: bold;\r\n z-index: ${zIndex.stickyHeader};\r\n\r\n display: ${(props) => (props.show ? 'flex' : 'none')};\r\n flex-direction: column;\r\n justify-content: center;\r\n align-items: center;\r\n\r\n &:hover .fa-angle-up {\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n .circle {\r\n border-radius: 50%;\r\n background-color: #fff;\r\n border: 0.2rem solid ${({ theme }) => theme.colors.primary};\r\n width: 2rem;\r\n height: 2rem;\r\n }\r\n`\r\n","import React, { useEffect, useState } from 'react'\r\nimport { faAngleUp } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { StyledScrollButton } from './ScrollButton.styled'\r\n\r\nconst ScrollButton = () => {\r\n const [show, setShow] = useState(false)\r\n\r\n useEffect(() => {\r\n const toggleVisible = () => {\r\n const scrolled = document.documentElement.scrollTop\r\n if (scrolled > 300) {\r\n setShow(true)\r\n } else if (scrolled <= 300) {\r\n setShow(false)\r\n }\r\n }\r\n window.addEventListener('scroll', toggleVisible)\r\n\r\n return () => window.removeEventListener('scroll', toggleVisible)\r\n }, [])\r\n\r\n const scrollToTop = () => {\r\n window.scrollTo({\r\n top: 0,\r\n behavior: 'smooth'\r\n })\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n TOP\r\n \r\n )\r\n}\r\n\r\nexport default ScrollButton\r\n","export const BMWIconNew = () => {\r\n return (\r\n \r\n )\r\n}\r\nexport default BMWIconNew\r\n","import { chunk } from 'lodash'\r\nimport { faChevronRight, faChevronLeft } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { useState, useEffect, useContext } from 'react'\r\nimport { Carousel, Col, Row } from 'react-bootstrap'\r\nimport { LazyLoadImage } from 'react-lazy-load-image-component'\r\nimport { IVehicleImage } from 'types/vehicleTypes'\r\nimport 'react-lazy-load-image-component/src/effects/blur.css'\r\nimport { StyledVehicleDetailCarousel, StyledVehicleDetailImage } from './VehicleDetailImage.style'\r\nimport BMWIconNew from 'images/icon/BMWIconNew'\r\nimport { SliderContext } from 'contexts/SliderContext'\r\ninterface IProps {\r\n mainImageUrl: string\r\n images: IVehicleImage[]\r\n vehicleInstance: number\r\n isDSI?: boolean\r\n}\r\n\r\nconst pageSize = 4\r\n\r\nexport const VehicleDetailImage = ({ mainImageUrl, images, vehicleInstance, isDSI = false }: IProps) => {\r\n const { setDisplaySlider, setSliderData, selectedImageID, selectedVehicle } = useContext(SliderContext)\r\n const [pageNumber, setPageNumber] = useState(0)\r\n const [imageUrl, setImageUrl] = useState('')\r\n const [canLoadImage, setCanLoadImage] = useState(true)\r\n\r\n const handleSelect = (selectedIndex: number) => {\r\n setPageNumber(selectedIndex)\r\n }\r\n const pages = chunk(images, pageSize)\r\n\r\n const handlImageChange = (imageUrl) => {\r\n setImageUrl(imageUrl)\r\n setCanLoadImage(true)\r\n }\r\n\r\n const handleBrokenImageURL = (event) => {\r\n setCanLoadImage(false)\r\n event.target.error = null\r\n }\r\n\r\n useEffect(() => {\r\n if (mainImageUrl) {\r\n setImageUrl(mainImageUrl)\r\n }\r\n }, [mainImageUrl])\r\n\r\n useEffect(() => {\r\n if (selectedImageID && selectedVehicle === vehicleInstance) {\r\n let imgIndex = images.findIndex((x) => x.ID === selectedImageID)\r\n imgIndex = imgIndex === -1 ? 0 : imgIndex\r\n setImageUrl(images[imgIndex]?.LocalThumbImageURL || images[imgIndex]?.LocalImageURL)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [selectedImageID, images])\r\n\r\n return (\r\n \r\n \r\n {images?.length <= 0 || !canLoadImage ? (\r\n \r\n ) : (\r\n
{\r\n setSliderData(images.map((image) => ({ ...image, Description: isDSI ? '' : image.Description })))\r\n setDisplaySlider(\r\n !!imageUrl,\r\n images.find((x) => x.LocalThumbImageURL === imageUrl || x.ImageURL === imageUrl)?.ID,\r\n vehicleInstance\r\n )\r\n }}\r\n />\r\n )}\r\n \r\n {images?.length > 1 && (\r\n }\r\n prevIcon={}\r\n >\r\n {pages.map((currentPage, index) => (\r\n \r\n \r\n {currentPage.map((item, index) => (\r\n \r\n handlImageChange(item.LocalThumbImageURL || item.ImageURL)}\r\n />\r\n \r\n ))}\r\n
\r\n \r\n ))}\r\n \r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default VehicleDetailImage\r\n","import { saveVehicleLevelWatchList } from 'apis/dashboardApis'\r\nimport { VehicleDetailsView } from 'common/constants'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { createContext, PropsWithChildren, useState } from 'react'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { SellerDisclosure } from 'types/inspectionTypes'\r\nimport { IVehicleData } from 'types/vehicleTypes'\r\n\r\nexport interface IVehicleContextProps {\r\n vehicleData: IVehicleData\r\n showRemoveBid?: boolean\r\n onRemoveBid?: () => void\r\n errorMessage?: string\r\n isVDP?: boolean\r\n loading?: boolean\r\n selfInspection?: SellerDisclosure\r\n retailView?: boolean\r\n viewStyle?: VehicleDetailsView\r\n}\r\n\r\nexport interface IVehicleContext extends IVehicleContextProps {\r\n showRemoveBid?: boolean\r\n editingNote: boolean\r\n setEditingNote: (editing: boolean) => void\r\n vehicleWatchListState: IVehicleWatchListState\r\n}\r\n\r\nexport const VehicleContext = createContext(null)\r\n\r\ninterface IVehicleWatchListState {\r\n isSaving?: boolean\r\n saveWatchList: () => void\r\n}\r\n\r\nexport const VehicleContextProvider = ({\r\n vehicleData,\r\n showRemoveBid,\r\n onRemoveBid,\r\n errorMessage,\r\n children,\r\n isVDP,\r\n selfInspection,\r\n loading,\r\n retailView,\r\n viewStyle\r\n}: PropsWithChildren) => {\r\n const [editingNote, setEditingNote] = useState(false)\r\n const [isSavingWatchList, setIsSavingWatchList] = useState(false)\r\n const { updateVehicleData } = useVehicleStore((state) => state)\r\n const { userInteraction } = useDtmAnalytics()\r\n\r\n const saveWatchList = async () => {\r\n try {\r\n setIsSavingWatchList(true)\r\n const response = await saveVehicleLevelWatchList({\r\n VehicleInstanceID: vehicleData.vehicle.InstanceID,\r\n RemoveVehicle: !!vehicleData.vehicle.WatchListID,\r\n SaleChannelID: vehicleData.vehicle.SaleChannelID,\r\n SaleEventID: vehicleData.vehicle.SaleEventID\r\n })\r\n vehicleData.vehicle.WatchListID = response.Value\r\n const customName = vehicleData.vehicle.WatchListID ? 'Add to Watchlist' : 'Remove from Watchlist'\r\n userInteraction(`${window.webData.pageName} : ${customName}`, [\r\n { auctionInfo: vehicleData.auctionInfo, VIN: vehicleData.vehicle.VIN }\r\n ])\r\n\r\n updateVehicleData(vehicleData)\r\n } catch (error) {\r\n console.log('SAVE WATCHLIST ERROR: ' + error)\r\n } finally {\r\n setIsSavingWatchList(false)\r\n }\r\n }\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}\r\n","import { borderColorSecondary, colorBackgroundCarfaxItem, mediumScreen, smallScreen } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledCarfaxAdvantage = styled.div`\r\n font-family: 'BMWGroup Regular', sans-serif;\r\n font-size: 1.1rem;\r\n\r\n display: flex;\r\n flex: 1;\r\n\r\n .carfax-advanced-icon {\r\n cursor: none;\r\n }\r\n\r\n @media (max-width: ${smallScreen}) {\r\n width: 100%;\r\n font-size: 1rem;\r\n flex-wrap: wrap;\r\n }\r\n\r\n @media (max-width: ${mediumScreen}) {\r\n min-width: auto;\r\n flex-wrap: wrap;\r\n width: 100%;\r\n }\r\n`\r\n\r\nexport const StyledCarfaxAdvantageTitleImage = styled.div`\r\n padding: 1rem 1rem;\r\n height: 4.5rem;\r\n flex-basis: 11.8rem;\r\n background-color: ${({ theme }) => theme.colors.carfaxBackground};\r\n\r\n @media print {\r\n background-color: ${({ theme }) => theme.colors.carfaxBackground};\r\n -webkit-print-color-adjust: exact;\r\n }\r\n img {\r\n width: 10rem;\r\n }\r\n\r\n @media (max-width: ${mediumScreen}) {\r\n width: 100%;\r\n text-align: center;\r\n flex-basis: auto;\r\n }\r\n`\r\n\r\nexport const StyledCarfaxAdvantageItem = styled.div`\r\n width: calc((100% - 11.8rem) / 4);\r\n float: left;\r\n background-color: ${colorBackgroundCarfaxItem};\r\n border: 0.1rem solid ${borderColorSecondary};\r\n height: 4.5rem;\r\n padding-left: 1rem;\r\n overflow-y: hidden;\r\n text-overflow: ellipsis;\r\n\r\n img {\r\n width: 2.5rem;\r\n height: 2.5rem;\r\n float: left;\r\n margin: 1rem 0.5rem;\r\n }\r\n .snapshot-item-content {\r\n display: table-cell;\r\n height: 4.5rem;\r\n vertical-align: middle;\r\n line-height: 2rem;\r\n }\r\n\r\n .carfax-item-count {\r\n background: orange;\r\n color: #fff;\r\n border-radius: 50%;\r\n padding: 0 1rem;\r\n top: -2.5rem;\r\n margin-left: -0.5rem;\r\n float: left;\r\n position: relative;\r\n }\r\n\r\n @media (max-width: ${mediumScreen}) {\r\n width: 50%;\r\n border: 0.1rem solid ${borderColorSecondary};\r\n }\r\n\r\n @media print {\r\n background-color: ${colorBackgroundCarfaxItem};\r\n -webkit-print-color-adjust: exact;\r\n }\r\n`\r\nexport const StyledNoCarfaxItem = styled.div`\r\n background-color: ${colorBackgroundCarfaxItem};\r\n line-height: 4.5rem;\r\n padding-left: 1rem;\r\n flex: 1;\r\n\r\n span {\r\n white-space: nowrap;\r\n }\r\n\r\n @media (max-width: ${smallScreen}) {\r\n width: 100%;\r\n }\r\n\r\n @media print {\r\n background-color: ${colorBackgroundCarfaxItem};\r\n -webkit-print-color-adjust: exact;\r\n }\r\n`\r\n","import {\r\n StyledCarfaxAdvantage,\r\n StyledCarfaxAdvantageItem,\r\n StyledCarfaxAdvantageTitleImage,\r\n StyledNoCarfaxItem\r\n} from './CarfaxAdvantage.styled'\r\nimport { ICarFaxSnapshotItem } from 'types/vehicleTypes'\r\nimport { carfaxIcon } from 'common/constants'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { Rules } from 'common/rules'\r\ninterface IProps {\r\n snapshotList: ICarFaxSnapshotItem[]\r\n}\r\n\r\nexport const CarfaxAdvantage = ({ snapshotList }: IProps) => {\r\n const isInRule = useGlobalStore((state) => state.isInRule)\r\n\r\n const viewCarfaxAdvantage = isInRule(Rules.VIEW_CARFAX_ADVANCED)\r\n\r\n if (!viewCarfaxAdvantage) {\r\n return <>>\r\n }\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n {snapshotList?.length > 0 ? (\r\n snapshotList.map((item, index) => (\r\n \r\n {item.Icon && (\r\n
\r\n )}\r\n {item.Value}\r\n {item.Value !== 'N/A' && item.ValueCount >= 0 && (\r\n {item.ValueCount}\r\n )}\r\n \r\n ))\r\n ) : (\r\n \r\n No CARFAX Snapshot items available\r\n \r\n )}\r\n \r\n )\r\n}\r\n","import { theme } from 'core/skins/NISSAN/theme'\r\nimport { ISearchVehiclesRequest } from 'types/vehicleTypes'\r\n\r\nexport const BMW_VENDOR_CODE = 'BMWUS001'\r\nexport const NISSAN_VENDOR_CODE = 'NISUS001'\r\n\r\nexport const PageSizeOptions = [25, 50, 100]\r\nexport const RECORDS_PER_PAGE_TEXT = 'Records per page:'\r\nexport const DEFAULT_PAGE_SIZE = 25\r\nexport const DEFAULT_BIG_PAGE_SIZE = 50\r\nexport const DEFAULT_HUGE_PAGE_SIZE = 100\r\nexport const DEFAULT_SMALL_PAGE_SIZE = 5\r\nexport const CONTINUE = 'Continue'\r\nexport const SUBMIT = 'Submit'\r\nexport const BMW_TEXT = 'BMW'\r\nexport const MEDIUM_SLIDER_ITEM_SIZE = 4\r\nexport const BIG_SLIDER_ITEM_SIZE = 8\r\nexport const HUGE_SLIDER_ITEM_SIZE = 12\r\nexport const VEHICLE_PROPERTIES_TO_HIDE = ['DD_CONDITION', 'MMR', 'VEHICLE_LOCATION', 'SALE_CHANNEL']\r\nexport const DEFAULT_ERROR_MESSAGE = 'An error has occurred. Please try again.'\r\nexport const PAGINATION_ITEM_SIZE = 10\r\nexport const CSRF_HEADER = '__RequestVerificationToken'\r\nexport const CSRF_TOKEN = 'RequestVerificationToken'\r\nexport const TERM_AND_CONDITION = 'Terms And Conditions'\r\nexport const FAQ = 'FAQs'\r\nexport const FRAME_DAMAGE_LABEL = 'Frame Damage: '\r\nexport const Return_To_Dashboard = 'Return_To_Dashboard'\r\n\r\nexport const CHARGEABLE_DAMAGE = 'ChargeableDamage'\r\nexport const NON_CHARGEABLE_DAMAGE = 'NonChargeableDamage'\r\nexport const UNKNOWN_CHARGEABLE_DAMAGE = 'UnknownChargeableDamage'\r\n\r\nexport const GND_DISPOSITION_RETURN_CONFIRM =\r\n 'You have indicated that the Lessee/Customer is returning their lease vehicle, please select from the following statements:'\r\nexport const GND_DISPOSITION_PURCHASE_CONFIRM =\r\n 'You have indicated the dealer is purchasing a lease vehicle. Please select one of the following statements that represents the lessee’s new contract:'\r\n\r\nexport const GENERAL_ERROR_MESSAGE = 'Required'\r\nexport const ERROR_ODOMETER_REQUIRED_MESSAGE = 'Odometer Reading is required'\r\nexport const ERROR_ODOMETER_INVALID_INPUT = 'Please enter valid odometer reading'\r\nexport const ODOMETER_WARNING = 'Mileage entered is less than mileage on preterm inspection'\r\n\r\nexport const ERROR_VIN_REQUIRED_MESSAGE = 'Required'\r\nexport const ERROR_VIN_INVALID_LENGTH_MESSAGE = 'VIN must be 17 characters'\r\nexport const ERROR_VIN_INVALID_INPUT_MESSAGE = 'You have entered an invalid VIN. Please re-enter.'\r\n\r\nexport const ERROR_EMAILS_REQUIRED_MESSAGE = 'You must enter one or more email address(es)'\r\nexport const ERROR_EMAILS_INVALID_INPUT_MESSAGE = 'Invalid email addess(es), please re-enter valid email address(es)'\r\nexport const ERROR_EMAILS_LIST_INVALID_INPUT_MESSAGE =\r\n 'Email address list is invalid. Please enter a valid list of emails, seperated by semi-colons'\r\n\r\nexport const ERROR_LESSEE_SIGNATURE_REQUIRED_MESSAGE = 'Lessee Signature is required'\r\nexport const ERROR_RETAILER_SIGNATURE_REQUIRED_MESSAGE = 'Retailer Signature is required'\r\n// Initial query payload for the SearchVehicle request\r\nexport const AVAILABLE_INVENTORY_INIT_QUERY: ISearchVehiclesRequest = {\r\n PageNumber: 0,\r\n PageSize: 25,\r\n QuickSearch: false,\r\n ReturnVehicles: false,\r\n ReturnZeroCountFilters: false,\r\n Ids: [],\r\n FilterOptions: {\r\n IsReserveMetVehicles: false,\r\n IsRecentlyAddedVehicles: false\r\n },\r\n SearchQuery: {\r\n ReturnOnlyVehicles: false,\r\n SearchFilters: [],\r\n SortBy: [],\r\n StatusIds: []\r\n }\r\n}\r\n\r\nexport const SRP_INIT_QUERY: ISearchVehiclesRequest = {\r\n ...AVAILABLE_INVENTORY_INIT_QUERY,\r\n ReturnVehicles: true,\r\n SearchQuery: {\r\n ...AVAILABLE_INVENTORY_INIT_QUERY.SearchQuery,\r\n ReturnOnlyVehicles: true\r\n }\r\n}\r\n\r\nexport const SRP_FILTERS_QUERY: Omit = {\r\n ...AVAILABLE_INVENTORY_INIT_QUERY\r\n}\r\n\r\nexport const MODEL_GROUP_MAPPER: { DisplayText: string; Value: string }[] = [\r\n { DisplayText: 'Hybrids', Value: 'Hybrid' }\r\n]\r\n\r\nexport const AVAILABLE_INVENTORY_MAPPER: { DisplayText: string; Value: string }[] = [\r\n //Body Styles\r\n { DisplayText: 'Crossover & SUVs', Value: 'Sport Utility,Station Wagon' },\r\n { DisplayText: 'Cars', Value: '4dr Car' },\r\n {\r\n DisplayText: 'Trucks',\r\n Value:\r\n 'Truck,Crew Cab Pickup,Crew Cab Pickup - Short Bed,Extended Cab Pickup,Full-size Cargo Van,Full-size Passenger Van,Mini-van, Cargo,Mini-van, Passenger,Regular Cab Pickup'\r\n },\r\n { DisplayText: 'Sport Cars', Value: '2dr Car' },\r\n\r\n //Fuel Types\r\n { DisplayText: 'Gasoline', Value: 'Gasoline,Diesel Fuel,Gasoline Fuel' },\r\n { DisplayText: 'Fully Electric', Value: 'Electric Fuel System,Plug-In Electric Fast Charge,Electric Fuel,Electric' },\r\n {\r\n DisplayText: 'Hybrid',\r\n Value: 'Gas/Electric Hybrid,Flex Fuel Capability,Flex Fuel,Gasoline/Electric Fuel,Gasoline/Electric'\r\n },\r\n\r\n { DisplayText: 'BodyStyle', Value: 'Body Style' },\r\n { DisplayText: 'FuelType', Value: 'Fuel Type' }\r\n]\r\n\r\nexport const AVAILABLE_INVENTORY_HEADING: Record = {\r\n BodyStyle: ['Crossover & SUVs', 'Cars', 'Trucks', 'Sport Cars'],\r\n FuelType: ['Gasoline', 'Hybrid', 'Fully Electric'],\r\n Make: ['Nissan', 'Infiniti']\r\n}\r\n\r\nexport const GENERIC_NO_VEHICLE_AVAILABLE_MESSAGE = 'No vehicles available.'\r\nexport const NO_NEW_INVENTORY_MESSAGE = 'No new inventory.'\r\n\r\nexport const SessionStorageKey = {\r\n SEARCH_FILTERS: 'SearchFilters',\r\n SEARCH_DESCRIPTION: 'SearchDescription',\r\n SEARCH_ID: 'SearchID',\r\n QUERY_FILTERS: 'QueryFilters',\r\n PAGE_SELECTED: 'PageSelected',\r\n SESSION_SORT: 'SessionSort',\r\n PAGE_SIZE: 'PageSize',\r\n VEHICLE_INSTANCES: 'vehicleInstances',\r\n FILTER_OPTION: 'FilterOptions',\r\n LIST_BREADCRUMB: 'breadCrumb_Listing',\r\n DETAIL_BREADCRUMB: 'breadCrumb_Detail',\r\n SIGNAL_R_CONNECTION_TRY_RECOUNT: 'signalRConnectionRetryCount',\r\n USER_LOCATION: 'UserLocation',\r\n SCROLL_TO_VIN: 'ScrollToVin',\r\n VIEW_VEHICLE_LIST: 'ViewVehicleMode',\r\n GROUND_VIN: 'groundVIN'\r\n}\r\n\r\nexport const assetFolders = {\r\n Infiniti: 'Infiniti',\r\n Independent: 'Independent',\r\n Nissan: 'Nissan',\r\n Guest: undefined\r\n}\r\n\r\nexport const ImageType = {\r\n DAMAGE_IMAGE: 'Damage Image'\r\n}\r\n\r\nexport const DefaultFilterOptions = {\r\n IsReserveMetVehicles: false,\r\n IsRecentlyAddedVehicles: false\r\n}\r\n\r\nexport const zIndex = {\r\n elevated: 10,\r\n floatingControls: 2, // This layer stays above Bootstrap custom controls and carousel navigators\r\n pageHeader: 3,\r\n menu: 20,\r\n subMenu: 1060,\r\n stickyHeader: 1020,\r\n stickyAlert: 1021,\r\n modal: 1050,\r\n navbarMobile: 1300,\r\n loader: 1400\r\n // carousel-indicators: 15\r\n} as const\r\n\r\nexport const VehicleStatuses = {\r\n SoldNotFunded: 4,\r\n OnSale: 36\r\n}\r\nexport const VehicleOfferStatuses = {\r\n OfferCountered: 3\r\n}\r\n\r\nexport const VehicleOffers = {\r\n AWAITING: 1\r\n}\r\n\r\nexport const MenuExclusionList = [{ name: 'RDP_MyAccount', childrens: ['RDP_MyProfile'] }]\r\nexport const FooterMenuExclusionList = ['RDP_ContactUs']\r\n\r\nexport const vendorImages = {\r\n rightLogo: '/content/custom/NISUS001/{assetFolder}/logo-right.png',\r\n whiteLogo: '/content/custom/NISUS001/{assetFolder}/logo-right-white.png',\r\n noModelImage: '/content/img/AwaitingCarImage.png'\r\n}\r\n\r\nexport const enum BaseVehicleSearchCriteriaColumn {\r\n Make = 1,\r\n Model = 3,\r\n VIN = 6,\r\n ModelYear = 79,\r\n Proximity = 1016,\r\n Promotion = 1027,\r\n NewInventory = 1028,\r\n DecreasedPrice = 1029,\r\n DisclosurePresent = 1030,\r\n OdometerCustomRange = 1032,\r\n VehicleConditionCode = 1033,\r\n DriveTrain = 1019\r\n}\r\n\r\nexport const MIN_MATCH_CHAR_LENGTH = 2\r\n\r\nexport const DefaultSortBy = {\r\n // Unset the name by default, so that we can query\r\n // and using the name returned from the API\r\n //\r\n // This will prevent hardcoded name not match with user's language pref\r\n Name: 'Vehicle Details - ↑',\r\n Value: 'Title ASC',\r\n SortOrder: 1,\r\n DBFieldName: 'Title'\r\n}\r\n\r\nexport const carfaxIcon = {\r\n carfaxTitleLogo: '/content/img/partners/carfax-title-logo.png',\r\n carfaxBaseUrl: '/content/img/partners/'\r\n}\r\n\r\nexport const BUY_VEHICLE_NO_ACTIVITY = {\r\n WATCH_LIST: 'Once you add vehicles to your watch list, they will appear here.',\r\n CURRENT_BIDS: 'Once you place bids on vehicles, they will appear here.',\r\n SAVE_SEARCH: 'You do not have any searches currently saved.',\r\n SEARCH_RESULTS: 'We were not able to find any vehicles that matched your criteria.'\r\n}\r\n\r\nexport const exportViews = {\r\n Excel: 1,\r\n PDF: 2\r\n}\r\nexport const SELECT_DISPLAY_LIMIT = 3\r\nexport const SelfArrangedTransportProviderId = 3\r\n\r\nexport enum BidAmountTypeOptions {\r\n CurrentBidAmount = 'CurrentBidAmount',\r\n UpdateBidAmount = 'UpdateBidAmount'\r\n}\r\n\r\nexport const BuyItNowPrice = 99999\r\n\r\nexport const enum VehicleDetailsView {\r\n List = 'list',\r\n Grid = 'grid'\r\n}\r\n\r\nexport const EnterKeyCharCode = 13\r\n\r\nexport const enum TyreStatus {\r\n GOOD = 'good',\r\n NORMAL = 'normal',\r\n BAD = 'bad'\r\n}\r\nexport const enum Tyres {\r\n FRONT_LEFT_TIRE,\r\n FRONT_RIGHT_TIRE,\r\n REAR_LEFT_TIRE,\r\n REAR_RIGHT_TIRE,\r\n SPARE_TIRE\r\n}\r\n\r\nexport const TyresDescriptionValue = {\r\n [Tyres.FRONT_LEFT_TIRE]: ['FRONT LEFT TIRE', 'LFRNT'],\r\n [Tyres.FRONT_RIGHT_TIRE]: ['FRONT RIGHT TIRE', 'RFRNT'],\r\n [Tyres.REAR_LEFT_TIRE]: ['REAR LEFT TIRE', 'LREAR'],\r\n [Tyres.REAR_RIGHT_TIRE]: ['REAR RIGHT TIRE', 'RREAR'],\r\n [Tyres.SPARE_TIRE]: ['SPARE TIRE', 'SPARE']\r\n}\r\n\r\nexport const TireTreadDepthRange = [4, 6, 32]\r\n\r\nexport const enum WidgetConfigurationDetails {\r\n WIDGET_SPECIFICS = 'Widget_Specifics',\r\n WIDGET_EQUIOMENT = 'Widget_Equipment',\r\n WIDGET_DAMAGEUPSTREAM = 'Widget_DamageUpstream',\r\n WIDGET_DAMAGEGROUNDEDEXCLUSIVE = 'Widget_DamageGroundedExclusive',\r\n WIDGET_PROMOTIONS = 'Widget_Promotions',\r\n WIDGET_ANNOUNCEMENTS = 'Widget_Announcements',\r\n WIDGET_PACKAGES = 'Widget_Packages',\r\n WIDGET_HISTORY = 'Widget_History',\r\n WIDGET_CONDITION = 'Widget_Condition',\r\n WIDGET_DAMAGE = 'Widget_Damage',\r\n WIDGET_TIRE = 'Widget_Tire',\r\n WIDGET_ADDITIONAL = 'Widget_Additional',\r\n WIDGET_DISCLAIMER = 'Widget_Disclaimer'\r\n}\r\n\r\nexport const DEFAULT_EXPAND_FILTERS_NUMBER = 10\r\nexport const fullScreenIcon = {\r\n zoomOutLogo: '/content/img/zoom_out.png',\r\n zoomInLogo: '/content/img/zoom_in.png'\r\n}\r\n\r\nexport const SELECTED_SEARCH_FILTERS_LIMIT = 5\r\n\r\nexport const PROXIMITY_FILTERS = [99999, 25, 50, 100, 200, 500, 1000]\r\n\r\nexport const enum RangeFieldIds {\r\n PROXIMITY_FIELD_ID = 1016,\r\n ODOMETERCUSTOMRANGE_FIELD_ID = 1032,\r\n VEHICLECONDITONCODE_FIELD_ID = 1033\r\n}\r\n\r\nexport const RANGE_FIELD_ID = [\r\n RangeFieldIds.ODOMETERCUSTOMRANGE_FIELD_ID,\r\n RangeFieldIds.PROXIMITY_FIELD_ID,\r\n RangeFieldIds.VEHICLECONDITONCODE_FIELD_ID\r\n]\r\n\r\nexport const LogoFooter = '/content/img/Private-Store-by-Manheim.png'\r\n\r\nexport const MY_ACTIVITY_YTD = {\r\n GROUNDED: 'Grounded',\r\n GROUNDED_PURCHASED: 'Grounded Purchased',\r\n WEB_AUCTION_PURCHASED: 'Web Auction Purchased'\r\n}\r\n\r\nexport const GROUNDING_OVERVIEW_SECTION = {\r\n EXPIRING_SOON: 'Expiring Soon',\r\n EXPIRING_TODAY: 'Expiring Today',\r\n GROUNDING_OVERDUE: 'Overdue Mandantory Purchases',\r\n PRIVATE_EXCLUSIVE_MARKET: 'Private Exclusive Market',\r\n AWAITING_INSPECTION: 'Awaiting Inspection',\r\n AWAITING_PRICING: 'Awaiting Pricing'\r\n}\r\n\r\nexport const DashboardGrounding = {\r\n PENDING_OFFERS: 0,\r\n GROUNDING_EXPIRING_SOON: 1,\r\n GROUNDING_EXPIRING_TODAY: 2,\r\n GROUNDING_OVERDUE: 3,\r\n GROUNDING_AWAITING_PRICING: 4,\r\n GROUNDING_AWAITING_INSPECTION: 5\r\n}\r\n\r\nexport const enum AddressTypes {\r\n HEAD_OFFICE = 1,\r\n INVOICE = 2,\r\n BRANCH_OFFICE = 3,\r\n GENERAL = 4,\r\n DEFLEET_AGENT = 5,\r\n COLLECTION = 6,\r\n AUCTION_CENTER = 7,\r\n DELIVERY = 8,\r\n TITLE_ADDRESS = 9,\r\n VEHICLE_PICKUP_LOCATION = 10,\r\n SELF_COLLECT = 11,\r\n USER_ADDRESS = 12,\r\n UPSTREAM_LOCATION = 13,\r\n SELLER_DISCLOSURE = 15,\r\n ALTERNATE_LOCATION = 16,\r\n CORPORATE_OFFICE = 17\r\n}\r\n\r\nexport enum RecallDetailStatus {\r\n HasOpenRecall = 1,\r\n NoOpenRecall = 2,\r\n NoData = 3\r\n}\r\n\r\nexport const enum SaveLocationOption {\r\n SAVE_TO_BUYER = 1,\r\n NOT_SAVE_TO_BUYER = 2\r\n}\r\n\r\nexport const BUYER_TYPE_ID = {\r\n NISSAN_FRANCHISED: 907,\r\n INFINITI_FRANCHISED: 908,\r\n MDM: 909,\r\n INDEPENDENT: 911,\r\n NISSAN_FRANCHISE_WITH_AA: 912,\r\n INFINITI_FRANCHISE_WITH_AA: 913,\r\n AUCTION: 914,\r\n CORPORATE_OFFICE_UPSTREAM: 915,\r\n CORPORATE_OFFICE_NON_UPSTREAM: 916\r\n}\r\nexport const VIN_CHARACTERS_REGEX = new RegExp(/[a-zA-Z0-9]/)\r\n\r\nexport const enum DocumentTypeEnum {\r\n TURNIN = 12,\r\n PURCHASE = 15,\r\n PAYOFF = 18\r\n}\r\n\r\nexport const DocumentType = [\r\n {\r\n id: DocumentTypeEnum.TURNIN,\r\n description: 'turn-in odometer statement'\r\n },\r\n {\r\n id: DocumentTypeEnum.PURCHASE,\r\n description: 'purchase confirmation'\r\n },\r\n {\r\n id: DocumentTypeEnum.PAYOFF,\r\n description: 'payoff Authorization form'\r\n }\r\n]\r\n","import { IRMSAuthModel } from 'types/rmsAuthModel'\r\nimport { parseJson } from 'utils/utils'\r\nimport { CSRF_TOKEN } from './constants'\r\n\r\nlocalStorage.setItem(CSRF_TOKEN, (document.querySelector('#antiForgery input') as HTMLInputElement)?.value)\r\n\r\nexport const rmsAuthModel = parseJson(document.getElementById('rmsAuthModel')?.innerHTML.trim()) as IRMSAuthModel\r\n","import styled from 'styled-components'\r\nimport { Button, Container } from 'react-bootstrap'\r\n\r\nimport { gridBreakPoints } from 'common/theme'\r\nexport const StyledHomeSectionHeaderTitle = styled.div<{ clickable: boolean }>`\r\n padding: 1.6rem 0;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n\r\n font-weight: 500;\r\n font-size: 1.8rem;\r\n text-align: center;\r\n\r\n height: 100%;\r\n\r\n background-color: ${({ theme }) => theme.colors.homeSectionBackgroundColor};\r\n color: ${({ theme }) => theme.colors.homeSectionColor};\r\n border-radius: 0.3rem;\r\n border: ${({ theme }) => `1px solid ${theme.colors.defaultTextColor}`};\r\n box-shadow: 0 0.2rem 0.2rem rgba(0, 0, 0, 0.25);\r\n :hover {\r\n ${(props) => props.clickable && 'cursor: pointer'}\r\n }\r\n .icon {\r\n margin-right: 0.5rem;\r\n }\r\n`\r\nStyledHomeSectionHeaderTitle.displayName = 'StyledHomeSectionHeaderTitle'\r\n\r\nexport const StyledHomeSectionHeaderActionSection = styled.div`\r\n padding-right: 1.25rem;\r\n\r\n /* v For the divider between section v */\r\n &:not(:first-child) {\r\n position: relative;\r\n\r\n &:before {\r\n content: '';\r\n display: block;\r\n position: absolute;\r\n left: 0;\r\n top: 15%;\r\n width: 0.2rem;\r\n height: 70%;\r\n background: #d4d4d4;\r\n border-radius: 2.5rem;\r\n\r\n padding: 1rem 0;\r\n }\r\n\r\n & > .btn-link:first-child {\r\n margin-left: 2rem;\r\n }\r\n }\r\n\r\n &:not(:last-child) {\r\n & > .btn-link:last-child {\r\n margin-right: 1rem;\r\n }\r\n }\r\n /* ^ For the divider between section ^ */\r\n`\r\nStyledHomeSectionHeaderActionSection.displayName = 'StyledHomeSectionHeaderActionSection'\r\n\r\nexport const StyledHomeSectionHeaderBanner = styled.div`\r\n &,\r\n & > div {\r\n height: 100%;\r\n }\r\n\r\n display: flex;\r\n align-items: center;\r\n\r\n /* Styles for mobile view */\r\n @media (max-width: ${gridBreakPoints.xl}) {\r\n margin: 0.1rem 0;\r\n padding: 0.3rem 0.3rem;\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.md}) {\r\n margin: 0.25rem 0;\r\n padding: 0.75rem 0.75rem;\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n flex-direction: column;\r\n gap: 1rem;\r\n\r\n ${StyledHomeSectionHeaderActionSection} {\r\n &:before {\r\n visibility: hidden;\r\n }\r\n\r\n &:not(:first-child) {\r\n & > .btn-link:first-child {\r\n margin-left: 0;\r\n }\r\n }\r\n\r\n &:not(:last-child) {\r\n & > .btn-link:last-child {\r\n margin-right: 0;\r\n }\r\n }\r\n }\r\n }\r\n`\r\nStyledHomeSectionHeaderBanner.displayName = 'StyledHomeSectionHeaderBanner'\r\n\r\nexport const StyledHomeSectionHeaderLink = styled(Button).attrs(({ className, variant, href }) => ({\r\n className: `d-flex align-items-center ${className ?? ''}`.trim(),\r\n variant: variant ?? 'link',\r\n href: href ?? null\r\n}))`\r\n font-size: 1.6rem;\r\n font-weight: 350;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n\r\n &:hover,\r\n &:active {\r\n text-decoration: none;\r\n }\r\n\r\n &:focus,\r\n &.focus {\r\n box-shadow: none;\r\n text-decoration: none;\r\n }\r\n\r\n &.active {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n font-weight: bold;\r\n position: relative;\r\n\r\n &:after {\r\n content: '';\r\n display: block;\r\n position: absolute;\r\n left: 0;\r\n bottom: -0.1rem;\r\n width: 100%;\r\n height: 0.5rem;\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n border-radius: 2.5rem;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledHomeSectionHeader = styled(Container).attrs({\r\n fluid: true\r\n})`\r\n border-radius: 0.3rem;\r\n\r\n box-shadow: 0 -0.025rem 0.2rem rgba(0, 0, 0, 0.15), 0 0.3rem 0.2rem rgba(0, 0, 0, 0.125);\r\n /* v Margin to create some space for the box-shadow v */\r\n margin-top: 0.1rem;\r\n margin-bottom: 0.3rem;\r\n /* ^ Margin to create some space for the box-shadow ^ */\r\n .header-col {\r\n height: 100%;\r\n }\r\n\r\n @media (min-width: ${gridBreakPoints.xl}) {\r\n .header-toggle {\r\n min-width: 20%;\r\n }\r\n\r\n ${StyledHomeSectionHeaderTitle} {\r\n padding-left: 1.4rem;\r\n }\r\n }\r\n\r\n @media print {\r\n -webkit-print-color-adjust: exact;\r\n\r\n a {\r\n text-decoration: none;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledHomeSectionBody = styled.div`\r\n padding: 2rem 5rem;\r\n background-color: ${({ theme }) => theme.colors.sectionContentBackgroundColor};\r\n position: relative;\r\n`\r\nexport const StyledRowInventory = styled.div`\r\n display: grid;\r\n grid-template-columns: repeat(5, 1fr);\r\n column-gap: 5rem;\r\n row-gap: 2rem;\r\n @media (max-width: ${gridBreakPoints.md}) {\r\n grid-template-columns: repeat(3, 1fr);\r\n }\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n grid-template-columns: 1fr;\r\n }\r\n`\r\n\r\nexport const StyledBuyerActivitySection = styled(StyledHomeSectionBody)`\r\n background-color: #fff;\r\n`\r\n\r\nexport const StyledHomeSection = styled.div`\r\n overflow: hidden;\r\n`\r\n\r\nStyledHomeSection.displayName = 'StyledHomeSection'\r\n","import { IDashboardVehicles, SavedSearchReceive } from './../types/vehicleTypes'\r\nimport { IAuctionInfo } from './../types/auctionTypes'\r\nimport { fetchAsync, postAsync } from 'common/fetch'\r\nimport {\r\n BuyerBaseVehicleSearchCriteria,\r\n DeliveryInformation,\r\n IBidOnVehicleRequest,\r\n IDeliveryQuote,\r\n IDocumentSignInfor,\r\n ISearchVehicleResponse,\r\n ISearchVehiclesRequest,\r\n IVehicleFeeRequest,\r\n IVehicleFeeResponse,\r\n IVehicleNote,\r\n IVehicleSearchDocument,\r\n SavedSearchData,\r\n WidgetConfigurationDetails\r\n} from 'types/vehicleTypes'\r\nimport { DocumentType, VehicleDocument, IBaseCollectionResponse, IBaseResponse, IApiState } from 'types/baseTypes'\r\nimport { GetBaseVehicleRequest, IVehicleData } from 'types/vehicleTypes'\r\nimport { SellerDisclosure } from 'types/inspectionTypes'\r\nimport { toUrlSearchParams } from 'utils/urlParams'\r\n\r\nexport const quickSearch = async (request: ISearchVehiclesRequest) => {\r\n return postAsync(`/api/vehicle/QuickSearch`, {\r\n body: request\r\n })\r\n}\r\n\r\nexport const searchAvailableInventory = async (request: ISearchVehiclesRequest) => {\r\n return postAsync(`/api/vehicle/SearchAvailableInventory`, {\r\n body: request\r\n })\r\n}\r\n\r\nexport const searchVehicles = async (request: ISearchVehiclesRequest) => {\r\n return postAsync(`/api/vehicle/SearchVehicles`, {\r\n body: request\r\n })\r\n}\r\n\r\nexport const getBaseVehicle = async (request: GetBaseVehicleRequest, biddingDealerId?: number) => {\r\n return postAsync>('/api/vehicle/GetBaseVehicle', {\r\n body: request,\r\n headers: {\r\n 'X-Actuos-BuyerID': biddingDealerId?.toString()\r\n }\r\n })\r\n}\r\n\r\nexport const saveDisclosure = async (request: IDocumentSignInfor) => {\r\n return postAsync>('/api/vehicle/SaveDisclosure', {\r\n body: request\r\n })\r\n}\r\n\r\nexport const addVehicleNotes = async (request: IVehicleNote) => {\r\n return postAsync('/api/vehicle/AddVehicleNotes', {\r\n body: request\r\n })\r\n}\r\n\r\nexport const getDetailedDeliveryInfo = async (request: IDeliveryQuote, biddingDealerId?: number) => {\r\n return postAsync('/api/vehicle/GetDetailedDeliveryInfo', {\r\n body: request,\r\n headers: {\r\n 'X-Actuos-BuyerID': biddingDealerId?.toString()\r\n }\r\n })\r\n}\r\n\r\nexport const getGenericPremium = async (request: IVehicleFeeRequest, biddingDealerId?: number) => {\r\n return postAsync('/api/vehicle/GetGenericPremium', {\r\n body: request,\r\n headers: {\r\n 'X-Actuos-BuyerID': biddingDealerId?.toString()\r\n }\r\n })\r\n}\r\n\r\nexport const bidOnVehicle = async (request: IBidOnVehicleRequest, biddingDealerId?: number) => {\r\n return postAsync>('/api/vehicle/BidOnVehicle', {\r\n body: request,\r\n headers: {\r\n 'X-Actuos-BuyerID': biddingDealerId?.toString()\r\n }\r\n })\r\n}\r\nexport const hideVehicleBidRow = async (request: IAuctionInfo) => {\r\n return postAsync>('/api/vehicle/HideVehicleBidRow', {\r\n body: request\r\n })\r\n}\r\n\r\nexport const getVehicleInformation = async (vehicleInstanceID: number) => {\r\n return postAsync('/api/vehicle/GetVehicleByID', {\r\n body: vehicleInstanceID\r\n })\r\n}\r\n\r\nexport const loadDayFiles = async (searchID?: number | string) => {\r\n return postAsync(`/api/vehicle/LoadDayFiles?${toUrlSearchParams({ searchID: searchID })}`)\r\n}\r\n\r\nexport const saveSearch = async (data: SavedSearchReceive) => {\r\n return postAsync('/api/vehicle/SaveSearch', {\r\n body: data\r\n })\r\n}\r\n\r\nexport const getSellerDisclosureByID = async (vehicleInstanceID: number) => {\r\n return postAsync('/api/vehicle/GetSellerDisclosureByID', {\r\n body: vehicleInstanceID\r\n })\r\n}\r\n\r\nexport const getVDPConfigurationDetails = () => {\r\n return fetchAsync(`/api/vehicle/GetVDPConfigurationDetails`)\r\n}\r\n\r\nexport const getVehicleHistoryByID = async (vehicleInstanceID: number) => {\r\n return postAsync('/api/vehicle/GetVehicleHistoryByID', {\r\n body: vehicleInstanceID\r\n })\r\n}\r\n\r\nexport const getDeliveryInfo = async (request: IDeliveryQuote) => {\r\n return postAsync('/api/vehicle/GetDeliveryInfo', {\r\n body: request\r\n })\r\n}\r\n\r\nexport const getMultipleVehicleDocuments = async (...vehicleInstanceIDs: number[]) => {\r\n return fetchAsync(\r\n `/api/vehicle/GetMultipleVehicleInstanceDocuments?${vehicleInstanceIDs\r\n .map((id) => `vehicleInstanceIDs[]=${id}`)\r\n .join('&')}&documentTypeID=${DocumentType.ExternalNoteAttachment}`\r\n )\r\n}\r\n\r\nexport const waiveVehicle = async (vehicleInstanceID: number) => {\r\n return postAsync('/api/grounding/WaiveVehicle', {\r\n body: { id: vehicleInstanceID }\r\n })\r\n}\r\n","export enum Rules {\r\n PAGE_RDP_Dashboard = 'PAGE_RDP_Dashboard',\r\n PAGE_RDP_SRP = 'PAGE_RDP_SRP',\r\n PAGE_RDP_CurrentBids = 'PAGE_RDP_CurrentBids',\r\n VIEW_WATCH_LIST = 'ViewWatchList',\r\n VIEW_SAVED_SEARCH_PAGE = 'PAGE_RDP_SavedSearch',\r\n VIEW_ADVANCED_SEARCH_PAGE = 'PAGE_RDP_AdvancedSearch',\r\n VIEW_GROUNDING_ACTIVITY = 'ViewBuyerGroundingConfiguartion',\r\n VIEW_GROUNDING_QUICK_START = 'ViewGroundingQuickStart',\r\n VIEW_DASHBOARD_GROUNDING_STATUS = 'ViewDashboardGroundingStatus',\r\n VIEW_CARFAX_ADVANCED = 'Carfax Advantage',\r\n VIEW_CHECKOUT_AT_MANHEIMCOM = 'viewCheckoutAtManheimCom',\r\n ENABLE_CARFAX = 'ENABLE_CARFAX',\r\n GROUNDING = 'grounding vehicle details'\r\n}\r\n","import { useCallback, useEffect, useState } from 'react'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IApiState } from 'types/baseTypes'\r\nimport shallow from 'zustand/shallow'\r\n\r\nexport const useFetch = (fn: () => Promise, allowedRules = [], deps = []) => {\r\n const isInRule = useGlobalStore((state) => state.isInRule, shallow)\r\n\r\n const [result, setResult] = useState>({\r\n loading: true\r\n })\r\n\r\n const doFetch = useCallback(async () => {\r\n if (!fn) return\r\n setResult({\r\n ...result,\r\n error: null,\r\n loading: true\r\n })\r\n\r\n if (allowedRules?.length > 0 && !allowedRules?.some((rule) => isInRule(rule))) {\r\n setResult({\r\n data: null,\r\n loading: false\r\n })\r\n return\r\n }\r\n\r\n try {\r\n const response = await fn()\r\n setResult({\r\n data: response,\r\n loading: false\r\n })\r\n } catch (error) {\r\n setResult({\r\n ...result,\r\n error,\r\n loading: false\r\n })\r\n }\r\n }, [fn, result])\r\n\r\n useEffect(() => {\r\n doFetch()\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, deps)\r\n\r\n return { ...result, refetch: doFetch } as IApiState\r\n}\r\n","import { BMW_VENDOR_CODE } from 'common/constants'\r\nimport {\r\n AnalyticsStore,\r\n getApplicationRevisionId,\r\n AnalyticsStorageKey,\r\n setCustomClick,\r\n getListings,\r\n getSearchParameters\r\n} from 'utils/analyticsUtils'\r\nimport { useCallback } from 'react'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { DtmSettings, DtmAnalyticsEvent, SRPDtmInfo, IListingModel, ICustomOptions } from 'types/dtmTypes'\r\nimport log from 'utils/logger'\r\n\r\nconst dtmSettings: DtmSettings = {\r\n events: 'rTEA,SRPView',\r\n siteCode: 'BMW Direct',\r\n platform: 'SinglePageApp',\r\n signature: '#analytics_om'\r\n}\r\n\r\nexport const useDtmAnalytics = () => {\r\n const userData = useGlobalStore((state) => state.userClaims)\r\n\r\n const dtmTraceWebEvent = (\r\n event: DtmAnalyticsEvent = 'pageView',\r\n { componentName, customClickName: alternativeClickName, listModel, userNote, searchData }: ICustomOptions = {}\r\n ) => {\r\n const { enableDtmAnalytics, environment, pageDetails, customClickName, pageName, pageRollup, tabName, loadStart } =\r\n AnalyticsStore\r\n if (!enableDtmAnalytics) {\r\n return\r\n }\r\n\r\n const { query, sortBy } = getSearchParameters(searchData)\r\n window.appEventData = window['appEventData'] || []\r\n window.webData = window['webData'] || {}\r\n const siteCode = userData.VendorCode === BMW_VENDOR_CODE ? dtmSettings.siteCode : 'RMSUS'\r\n const applicationCode = event === 'componentLoad' ? `${userData.VendorCode}:${componentName}` : userData.VendorCode\r\n // geolocation is handled by Adobe analytics framework, so we just need to ask for geolocation permission and not need to send any data\r\n let eventData: SRPDtmInfo = {\r\n event: event,\r\n events: dtmSettings.events,\r\n siteCode: siteCode,\r\n platform: dtmSettings.platform,\r\n signature: dtmSettings.signature,\r\n application: applicationCode,\r\n loginName: userData.Username,\r\n pageDetails: userData.VendorCode === BMW_VENDOR_CODE ? 'BMW Direct - ' + pageDetails : pageDetails,\r\n repID: userData.RepAuctionAccess?.toString(),\r\n sessionId: userData.SessionID,\r\n environment,\r\n applicationRevisionId: getApplicationRevisionId(),\r\n accountID: userData.CurrentBuyerID?.toString(),\r\n accountName: userData.DealershipName,\r\n pageName: componentName || pageName,\r\n pageRollup: pageRollup,\r\n tabName: tabName,\r\n customClickName: alternativeClickName || customClickName,\r\n loadTime: new Date().getTime() - (loadStart ? loadStart.getTime() : new Date().getTime()),\r\n pageType: event === 'componentLoad' ? 'component' : 'page',\r\n language: userData.LanguageCode,\r\n userNotes: userNote,\r\n query,\r\n sortBy\r\n } as any\r\n window.webData = eventData\r\n const listings = getListings(listModel, siteCode, userData.VendorCode)\r\n const appEventData = { ...eventData, listings }\r\n window.appEventData.push(appEventData)\r\n\r\n log.debug(new Date().toISOString(), appEventData)\r\n if (event === 'pageView' && sessionStorage.getItem(AnalyticsStorageKey.CUSTOM_CLICK_NAME)) {\r\n sessionStorage.removeItem(AnalyticsStorageKey.CUSTOM_CLICK_NAME)\r\n delete AnalyticsStore.customClickName\r\n }\r\n }\r\n\r\n const userInteraction = useCallback(\r\n (customClickName?: string, listModel?: IListingModel[], { userNote }: ICustomOptions = {}) => {\r\n if (customClickName) {\r\n setCustomClick(customClickName)\r\n }\r\n dtmTraceWebEvent('userInteraction', {\r\n customClickName,\r\n listModel,\r\n userNote\r\n })\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n },\r\n []\r\n )\r\n\r\n const endPageLoad = useCallback((listModel?: IListingModel[], { searchData }: ICustomOptions = {}) => {\r\n dtmTraceWebEvent('pageView', {\r\n listModel,\r\n searchData\r\n })\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n const endComponentLoad = useCallback((componentName?: string, listModel?: any[]) => {\r\n dtmTraceWebEvent('componentLoad', {\r\n componentName,\r\n listModel\r\n })\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n return { endPageLoad, endComponentLoad, userInteraction }\r\n}\r\n","import { isReactRoutes } from 'common/routes'\r\nimport React, { PropsWithChildren } from 'react'\r\nimport { NavLink as BsNavLink } from 'react-bootstrap'\r\nimport { Link as ReactLink } from 'react-router-dom'\r\nconst classNames = require('classnames')\r\n\r\ninterface IProps extends PropsWithChildren<{}> {\r\n to: string\r\n className?: string\r\n onClick?: (e?: any) => void\r\n}\r\nexport const NavLink = ({ to, children, className, ...props }: IProps) => {\r\n const isReactPath = isReactRoutes(to)\r\n\r\n return isReactPath ? (\r\n \r\n {children}\r\n \r\n ) : (\r\n \r\n {children}\r\n \r\n )\r\n}\r\n\r\nexport const Link = ({ to, children, className, ...props }: IProps) => {\r\n const isReactPath = isReactRoutes(to)\r\n\r\n return isReactPath ? (\r\n \r\n {children}\r\n \r\n ) : (\r\n \r\n {children}\r\n \r\n )\r\n}\r\n","import { isEmpty } from 'lodash'\r\nimport { IVehicleSearchDocument, ISearchFilterResult } from 'types/vehicleTypes'\r\nimport { BaseVehicleSearchCriteriaColumn } from './constants'\r\n\r\n// Common\r\nexport const stripHtml = (htmlStr: string): string => {\r\n return new DOMParser()\r\n .parseFromString(htmlStr, 'text/html')\r\n .documentElement.textContent.replace(/\\s{2,}|\\t{1,}/g, ' ')\r\n .trim()\r\n}\r\n\r\n// AvailableInventory\r\nexport const isAnyChilrenFiltersSelected = (filters: ISearchFilterResult[], filterFieldName: string) => {\r\n return filters.find((ft) => ft.FieldName === filterFieldName)?.ChildrenFilter?.some((cft) => cft.Selected)\r\n}\r\n\r\nexport const isAnyChildrenFilterExist = (\r\n filters: ISearchFilterResult[],\r\n filterFieldName: string,\r\n childrenFilterFieldName: string\r\n) => {\r\n return filters\r\n .find((ft) => ft.FieldName === filterFieldName)\r\n ?.ChildrenFilter?.some((cft) => cft.FieldName === childrenFilterFieldName)\r\n}\r\n\r\nexport const isAnyChildrenFilterExistValue = (\r\n filters: ISearchFilterResult[],\r\n filterFieldName: string,\r\n childrenFilterFieldName: string,\r\n value: string\r\n) => {\r\n return filters\r\n .find((ft) => ft.FieldName === filterFieldName)\r\n ?.ChildrenFilter?.some((cft) => cft.FieldName === childrenFilterFieldName && cft.Value === value)\r\n}\r\nexport const hasAnyChilrenFilter = (filters: ISearchFilterResult[], filterFieldName: string) => {\r\n return filters.find((ft) => ft.FieldName === filterFieldName)?.ChildrenFilter?.length > 0\r\n}\r\n\r\nexport const processVehicleSearchDocumentResult = (\r\n result: IVehicleSearchDocument[],\r\n filters: ISearchFilterResult[],\r\n filterFieldName: string,\r\n filterField: (r: IVehicleSearchDocument) => string\r\n) => {\r\n const processFilters = (childrenFilters: ISearchFilterResult[]) =>\r\n childrenFilters.filter((cft: ISearchFilterResult) => cft.Selected).map((cft: ISearchFilterResult) => cft.Value)\r\n\r\n if (isAnyChilrenFiltersSelected(filters, filterFieldName)) {\r\n return result.filter((r: IVehicleSearchDocument) =>\r\n processFilters([...filters.find((ft) => ft.FieldName === filterFieldName)?.ChildrenFilter]).includes(\r\n filterField(r)\r\n )\r\n )\r\n }\r\n\r\n return result\r\n}\r\n\r\nexport const resetChildrenFilters = (filters: ISearchFilterResult[], ...filterFieldNames: string[]) => {\r\n if (!isEmpty(filterFieldNames)) {\r\n return filterFieldNames?.forEach((filterFieldName) =>\r\n filters.find((ft) => ft.FieldName === filterFieldName)!.ChildrenFilter.forEach((cft) => (cft.Selected = false))\r\n )\r\n }\r\n\r\n return filters?.forEach((ft) => ft.ChildrenFilter.forEach((cft) => (cft.Selected = false)))\r\n}\r\n\r\nexport const selectChildrenFilter = (\r\n filters: ISearchFilterResult[],\r\n filterFieldName: string,\r\n ...selectedValues: string[]\r\n) => {\r\n return filters.forEach((filter) => {\r\n if (filter.FieldName === filterFieldName) {\r\n selectedValues?.forEach((selectedValue) => {\r\n if (filter.ChildrenFilter.find((childFilter) => childFilter.Value === selectedValue)) {\r\n filter.ChildrenFilter.find((childFilter) => childFilter.Value === selectedValue).Selected = true\r\n }\r\n })\r\n }\r\n })\r\n}\r\nexport const addDummyChildrenFilter = (\r\n filters: ISearchFilterResult[],\r\n fieldId: BaseVehicleSearchCriteriaColumn,\r\n fieldName: string,\r\n dbFieldName: string,\r\n value: string,\r\n selected: boolean = true\r\n) => {\r\n filters\r\n .find((ft) => ft.FieldName === fieldName)\r\n ?.ChildrenFilter?.push({\r\n FieldId: fieldId,\r\n FieldName: fieldName,\r\n DBFieldName: dbFieldName,\r\n FriendlyValue: value,\r\n Value: value,\r\n Selected: selected,\r\n MultiSelect: true,\r\n Operation: 1\r\n })\r\n}\r\n","import { rmsAuthModel } from 'common/rmsGlobal'\r\nimport { isEmpty } from 'lodash'\r\nimport { IVehicleInfo } from 'types/vehicleTypes'\r\nimport { toUrlSearchParams } from './urlParams'\r\n\r\nexport const buildMMRUrl = (mmrHost: string, vehicleInfo: IVehicleInfo) => {\r\n let mmrLink = `${mmrHost ?? 'https://mmr.manheim.com'}/?popup=true`\r\n\r\n if (isEmpty(vehicleInfo)) return mmrLink\r\n\r\n mmrLink += `&vin=${vehicleInfo.VIN}`\r\n const properties = vehicleInfo.Properties.filter((x) => x.ID === 1)\r\n\r\n // Mileage (Odometer)\r\n let prop = properties.find((p) => p.UIConstantName === 'MILEAGE')?.Description\r\n if (!isEmpty(prop)) mmrLink += `&mileage=${parseFloat(prop.replace(/,/g, ''))}`\r\n\r\n // Condition Grade\r\n prop = properties.find((p) => p.UIConstantName === 'DD_CONDITION')?.Description\r\n if (!isEmpty(prop)) mmrLink += `&condition=${prop}`\r\n\r\n mmrLink += '&country=US'\r\n\r\n return mmrLink\r\n}\r\n\r\nconst enableReactLinks = Boolean(+rmsAuthModel.systemSettings.ENABLE_REACT_LINKS)\r\nexport const getVdpUrl = (vehicleInstanceId: number) => {\r\n return enableReactLinks ? `/vehicle/${vehicleInstanceId}` : `/vehicles#detail/${vehicleInstanceId}`\r\n}\r\n\r\nexport const getWatchlistUrl = () => (enableReactLinks ? '/watchlist' : '/vehicles#watchlist')\r\nexport const getCurrentBidsUrl = () => (enableReactLinks ? '/managebids' : '/vehicles#currentBids')\r\nexport const getSearchUrl = () => (enableReactLinks ? '/search' : '/vehicles')\r\nexport const getSaveSearchUrl = () => '/vehicles#savedSearch'\r\n\r\nexport const getFilterSeachResultUrl = (filterField: string, filterValue: string) =>\r\n `/vehicles?filters=${filterField}@${filterValue}`\r\n\r\nexport const getAwaitingReportUrl = (\r\n minDateAwaitingInspection: string,\r\n maxDateAwaitingInspection: string,\r\n listOfVin: string\r\n) =>\r\n `/account#awaitingInspectionReport?${toUrlSearchParams({\r\n fromDate: minDateAwaitingInspection,\r\n toDate: maxDateAwaitingInspection,\r\n vin: listOfVin\r\n })}`\r\n\r\nexport const getBuyItNowUrl = (vehicleInstanceID: number) => `/vehicles#purchaseExclusive/${vehicleInstanceID}`\r\n","import { cardStyle } from 'components/Share/Card.styled'\r\nimport { VehicleContext } from 'modules/DealerVehicleManagement/VehicleContext'\r\nimport { PropsWithChildren, useContext } from 'react'\r\nimport LazyLoad from 'react-lazyload'\r\nimport styled from 'styled-components'\r\nimport { StockwaveData } from '../Stockwave/StockwaveData'\r\n\r\ninterface IProps {\r\n className?: string\r\n}\r\n\r\nexport const StyledVehicleLoader = styled(LazyLoad as any)`\r\n ${cardStyle}\r\n`\r\n\r\nexport const VehicleLoader = ({ children, className }: PropsWithChildren) => {\r\n const { vehicleData } = useContext(VehicleContext)\r\n const {\r\n vehicle: { VIN }\r\n } = vehicleData\r\n\r\n return (\r\n \r\n {VIN}\r\n \r\n \r\n }\r\n once\r\n >\r\n {children}\r\n \r\n )\r\n}\r\n","import { largeScreen, smallScreen } from 'common/theme'\r\nimport { VehicleLoader } from 'modules/VehicleList/VehicleLoader'\r\nimport { Col, Tooltip, Row, Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledTitleSection = styled(Row)``\r\n\r\nexport const StyledVehicleDetailsCard = styled(VehicleLoader)`\r\n background-color: #fff;\r\n flex: 1;\r\n border: 0.1rem solid #ddd;\r\n padding: 1rem 1rem 1rem 1rem;\r\n margin-top: 0;\r\n margin-bottom: 1.6rem;\r\n min-height: 25rem;\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: center;\r\n\r\n > .row {\r\n column-gap: 1.5rem;\r\n }\r\n\r\n .vehicle-detail-image-section {\r\n max-width: 40rem;\r\n position: relative;\r\n\r\n .custom-control.custom-checkbox {\r\n position: absolute;\r\n margin: 0.5rem;\r\n }\r\n .nav-link {\r\n padding: 0;\r\n }\r\n\r\n .stockwave-light-bulb-container {\r\n margin-left: 4rem;\r\n }\r\n }\r\n\r\n .carfax-advanced-section {\r\n margin-top: 0.8rem;\r\n @media (max-width: ${smallScreen}) {\r\n padding-left: inherit;\r\n }\r\n }\r\n\r\n ${StyledTitleSection} {\r\n display: flex;\r\n align-items: center;\r\n padding: 0 1.5rem;\r\n margin: 0;\r\n\r\n a {\r\n padding: 0;\r\n font-size: 2.4rem;\r\n color: ${({ theme }) => theme.colors.primary};\r\n\r\n margin-right: 0.8rem;\r\n font-weight: 600;\r\n\r\n &:active,\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n }\r\n }\r\n\r\n div[class^='col'] {\r\n padding-left: 0;\r\n padding-right: 0;\r\n }\r\n @media screen and (max-width: mediumScreen) {\r\n flex-direction: column;\r\n align-items: flex-start;\r\n }\r\n }\r\n\r\n .link-col {\r\n color: ${(props) => props.theme.colors.primary};\r\n\r\n display: flex;\r\n align-items: center;\r\n gap: 1.2rem;\r\n\r\n a {\r\n text-decoration: none;\r\n font-size: 1.5rem;\r\n\r\n &:hover {\r\n cursor: pointer;\r\n opacity: 0.5;\r\n }\r\n }\r\n\r\n .icon {\r\n margin-right: 0.4rem;\r\n }\r\n }\r\n\r\n .vehicle-info {\r\n margin-bottom: 1rem;\r\n gap: 0.8rem 0;\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n\r\n a {\r\n text-decoration: underline;\r\n }\r\n\r\n @media screen and (min-width: mediumScreen) {\r\n .vehicle-properties {\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n }\r\n }\r\n\r\n .true-frame-link {\r\n max-width: 8rem;\r\n\r\n &:empty {\r\n display: none;\r\n }\r\n }\r\n\r\n .carfax-link {\r\n font-weight: 500;\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n text-transform: uppercase;\r\n\r\n .icon {\r\n margin-right: 0;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledCarfaxCol = styled(Col)`\r\n display: flex;\r\n\r\n @media (max-width: ${largeScreen}) {\r\n width: 100%;\r\n }\r\n`\r\n\r\nexport const StyledRibbonContainer = styled.div`\r\n & span:not(:last-child) .ribbon {\r\n margin-right: 1.5rem;\r\n }\r\n\r\n & span .ribbon {\r\n margin-left: 0;\r\n }\r\n\r\n .ribbon-title {\r\n filter: brightness(0.75);\r\n }\r\n`\r\n\r\nexport const StyledInfoLabel = styled.span`\r\n font-weight: 700;\r\n\r\n margin-right: 0.375rem;\r\n`\r\nexport const StyledToolTip = styled(Tooltip)`\r\n .arrow {\r\n display: none;\r\n }\r\n .tooltip-inner {\r\n background-color: #fff;\r\n color: black;\r\n border: 0.1rem solid #ddd;\r\n border-radius: 0.5rem;\r\n max-width: 30rem;\r\n }\r\n`\r\n\r\nexport const VehicleVin = styled.div`\r\n font-size: 1.6rem;\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n margin-bottom: 1rem;\r\n`\r\n\r\nexport const PaperClipButton = styled(Button)`\r\n margin-left: 1rem;\r\n\r\n .fa-paperclip {\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n`\r\nexport const TitleVDP = styled.span`\r\n padding: 0;\r\n font-size: 2.4rem;\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n\r\n margin-right: 0.8rem;\r\n font-weight: 600;\r\n`\r\n","export const enum srpFilters {\r\n Promotion = 'Promotion',\r\n BodyStyle = 'Body Style',\r\n FuelType = 'Fuel Type',\r\n Make = 'Make',\r\n Model = 'Model',\r\n Year = 'Model Year'\r\n}\r\n","import { Alert } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\nimport { zIndex } from 'common/constants'\r\nexport const StyledAlertNotification = styled(Alert)`\r\n z-index: ${zIndex.stickyAlert};\r\n`\r\n","import { useSignalRStore } from 'store/useSignalRStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledAlertNotification } from './AlertNotification.styled'\r\n\r\nexport const AlertNotification = () => {\r\n const { showConnectionAlert, setShowConnectionAlert } = useSignalRStore((state) => state, shallow)\r\n return (\r\n <>\r\n {showConnectionAlert && (\r\n setShowConnectionAlert(false)}\r\n dismissible\r\n className=\"mb-0 sticky-top\"\r\n >\r\n \r\n Connection to real time bid information has been lost. Please\r\n window.location.reload()}>\r\n click here \r\n \r\n to reload this page\r\n
\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { useEffect } from 'react'\r\nimport { useLocation } from 'react-router-dom'\r\n\r\nexport default function ScrollToTop() {\r\n const { pathname } = useLocation()\r\n\r\n useEffect(() => {\r\n window.scrollTo(0, 0)\r\n }, [pathname])\r\n\r\n return null\r\n}\r\n","export enum GroundingRenderStep {\r\n GRD_ENTER_VIN = 0,\r\n GRD_OPTIONS = 1,\r\n GRD_TURN_IN = 2,\r\n GRD_RESULT = 3\r\n}\r\n","import { DefaultTheme } from 'styled-components'\r\n\r\nexport const GuestTheme: DefaultTheme = {\r\n colors: {\r\n primary: '#c3002f',\r\n tableStriped: '#e9e9e9',\r\n tableBorder: '#dee2e6',\r\n footer: '#232323',\r\n primaryDarken: '#0e233e',\r\n secondary: '#E3E4E5',\r\n linkColor: '#4270d2',\r\n linkColorLight: '#0083c6',\r\n inputBorder: '#d4d4d4',\r\n fontColor: '#5b5b5b',\r\n inputBackgroundColor: '#ffffff',\r\n mobileMenuBackground: '#f4f4f4',\r\n sectionContentBackgroundColor: '#f6f6f6',\r\n borderInput: '1px solid #d4d4d4',\r\n infoColor: '#6a8c9c',\r\n successColor: '#26ad77',\r\n warningColor: '#f90',\r\n dangerColor: '#b11926',\r\n ribbonInfoBackgroundColor: '#dae2e6',\r\n ribbonSuccessBackgroundColor: '#c9eadd',\r\n ribbonWarningBackgroundColor: '#ffe5bf',\r\n ribbonDangerBackgroundColor: '#ebc5c9',\r\n backgroundText: 'white',\r\n colorTextModal: '#f2dede',\r\n colorButtonDisabled: '#444',\r\n switchBackgroundColor: '#6f6f6f',\r\n headerFontColor: '#494949',\r\n defaultDealerDeactive: '#A94442',\r\n incentiveHeaderColor: '#3d6a3c',\r\n dropdownHoverColor: '#deebff',\r\n incentiveHeaderHoverColor: '#39a937',\r\n modalHeader: '#818181',\r\n carfaxBackground: '#3777bc',\r\n goodTireColor: '#406a3b',\r\n normalTireColor: '#e3c35e',\r\n badTireColor: '#ba0000',\r\n issueColor: '#b11926',\r\n defaultTextColor: '#000000',\r\n stickyTextColor: '#ffffff',\r\n darkGrayColor: '#606060',\r\n shadeGrayColor: '#333333',\r\n hoverConfirmButtonColor: '#a50129',\r\n\r\n //Cancel button colors\r\n cancelButtonBackgroundColor: '#ffffff',\r\n cancelButtonColor: '#000000',\r\n cancelButtonHoverBackgroundColor: '#000000',\r\n\r\n //Home Section Header\r\n homeSectionBackgroundColor: '#000000',\r\n homeSectionColor: '#ffffff',\r\n\r\n InfinitiOnlyColor: '#c3002f',\r\n\r\n hyperLinkColor: 'rgb(195, 0, 47)',\r\n hyperLinkHoverColor: 'rgb(165, 1, 41)',\r\n stepperCompleteColor: '#e18097',\r\n\r\n InfinitiLinkColor: '#c3002f',\r\n InfinitiLinkHoverColor: '#a50129'\r\n },\r\n headerSticky: {\r\n text: '#E3E4E5'\r\n },\r\n headerNotSticky: {\r\n text: '#000000',\r\n textHover: '#c3002f',\r\n spanUnderline: '#c3002f',\r\n subMenuBackground: '#ffffff'\r\n },\r\n carousel: {\r\n buttonBackground: '#000000',\r\n buttonColor: '#ffffff',\r\n buttonBorder: '#000000',\r\n buttonHoverBackground: '#333333',\r\n buttonHoverBorderColor: '#c3002f'\r\n },\r\n footer: {\r\n backgroundColor: '#232323',\r\n fontColor: '#fff'\r\n },\r\n logo: {\r\n left: 'vendor-main-logo.png',\r\n right: 'site_title-new.png?version=2'\r\n },\r\n fonts: {\r\n fontBase: 'Nissan AG Bold',\r\n fontRegular: 'NissanGroup Regular'\r\n }\r\n}\r\n","import { DefaultTheme } from 'styled-components'\r\n\r\nexport const IndependentTheme: DefaultTheme = {\r\n colors: {\r\n primary: '#c3002f',\r\n tableStriped: '#e9e9e9',\r\n tableBorder: '#dee2e6',\r\n footer: '#232323',\r\n primaryDarken: '#0e233e',\r\n secondary: '#E3E4E5',\r\n linkColor: '#4270d2',\r\n linkColorLight: '#0083c6',\r\n inputBorder: '#d4d4d4',\r\n fontColor: '#5b5b5b',\r\n inputBackgroundColor: '#ffffff',\r\n mobileMenuBackground: '#f4f4f4',\r\n sectionContentBackgroundColor: '#f6f6f6',\r\n borderInput: '1px solid #d4d4d4',\r\n infoColor: '#6a8c9c',\r\n successColor: '#26ad77',\r\n warningColor: '#f90',\r\n dangerColor: '#b11926',\r\n ribbonInfoBackgroundColor: '#dae2e6',\r\n ribbonSuccessBackgroundColor: '#c9eadd',\r\n ribbonWarningBackgroundColor: '#ffe5bf',\r\n ribbonDangerBackgroundColor: '#ebc5c9',\r\n backgroundText: 'white',\r\n colorTextModal: '#f2dede',\r\n colorButtonDisabled: '#444',\r\n switchBackgroundColor: '#6f6f6f',\r\n headerFontColor: '#494949',\r\n defaultDealerDeactive: '#A94442',\r\n incentiveHeaderColor: '#3d6a3c',\r\n dropdownHoverColor: '#deebff',\r\n incentiveHeaderHoverColor: '#39a937',\r\n modalHeader: '#818181',\r\n carfaxBackground: '#3777bc',\r\n goodTireColor: '#406a3b',\r\n normalTireColor: '#e3c35e',\r\n badTireColor: '#ba0000',\r\n issueColor: '#b11926',\r\n defaultTextColor: '#000000',\r\n stickyTextColor: '#ffffff',\r\n darkGrayColor: '#606060',\r\n shadeGrayColor: '#333333',\r\n hoverConfirmButtonColor: '#a50129',\r\n\r\n //Cancel button colors\r\n cancelButtonBackgroundColor: '#ffffff',\r\n cancelButtonColor: '#000000',\r\n cancelButtonHoverBackgroundColor: '#000000',\r\n\r\n //Home Section Header\r\n homeSectionBackgroundColor: '#000000',\r\n homeSectionColor: '#ffffff',\r\n\r\n InfinitiOnlyColor: '#c3002f',\r\n\r\n hyperLinkColor: 'rgb(195, 0, 47)',\r\n hyperLinkHoverColor: 'rgb(165, 1, 41)',\r\n stepperCompleteColor: '#e18097',\r\n\r\n InfinitiLinkColor: '#c3002f',\r\n InfinitiLinkHoverColor: '#a50129'\r\n },\r\n headerSticky: {\r\n text: '#000000',\r\n textHover: '#5b5b5b',\r\n backgroundColor: '#ffffff',\r\n spanUnderline: '#c3002f',\r\n subMenuBackground: '#ffffff',\r\n subMenuItemBorder: '#c3002f',\r\n subMenuItemHover: '#c3002f',\r\n userMenuFont: '#000000'\r\n },\r\n headerNotSticky: {\r\n text: '#000000',\r\n textHover: '#5b5b5b',\r\n spanUnderline: '#c3002f',\r\n subMenuBackground: '#ffffff',\r\n subMenuItemBorder: '#c3002f',\r\n subMenuItemHover: '#c3002f',\r\n userMenuFont: '#000000'\r\n },\r\n carousel: {\r\n buttonBackground: '#000000',\r\n buttonColor: '#ffffff',\r\n buttonBorder: '#000000',\r\n buttonHoverBackground: '#333333',\r\n buttonHoverBorderColor: '#000000'\r\n },\r\n footer: {\r\n backgroundColor: '#e5e5e5',\r\n fontColor: '#999'\r\n },\r\n logo: {\r\n left: 'vendor-main-logo.png',\r\n right: 'site_title-new.png?version=2'\r\n },\r\n fonts: {\r\n fontBase: 'Nissan AG Bold',\r\n fontRegular: 'NissanGroup Regular'\r\n }\r\n}\r\n","import { DefaultTheme } from 'styled-components'\r\n\r\nexport const InfinitiTheme: DefaultTheme = {\r\n colors: {\r\n primary: '#c3002f',\r\n tableStriped: '#e9e9e9',\r\n tableBorder: '#dee2e6',\r\n footer: '#232323',\r\n primaryDarken: '#0e233e',\r\n secondary: '#E3E4E5',\r\n linkColor: '#4270d2',\r\n linkColorLight: '#0083c6',\r\n inputBorder: '#d4d4d4',\r\n fontColor: '#5b5b5b',\r\n inputBackgroundColor: '#ffffff',\r\n mobileMenuBackground: '#f4f4f4',\r\n sectionContentBackgroundColor: '#f6f6f6',\r\n borderInput: '1px solid #d4d4d4',\r\n infoColor: '#6a8c9c',\r\n successColor: '#26ad77',\r\n warningColor: '#f90',\r\n dangerColor: '#b11926',\r\n ribbonInfoBackgroundColor: '#dae2e6',\r\n ribbonSuccessBackgroundColor: '#c9eadd',\r\n ribbonWarningBackgroundColor: '#ffe5bf',\r\n ribbonDangerBackgroundColor: '#ebc5c9',\r\n backgroundText: 'white',\r\n colorTextModal: '#f2dede',\r\n colorButtonDisabled: '#444',\r\n switchBackgroundColor: '#6f6f6f',\r\n headerFontColor: '#494949',\r\n defaultDealerDeactive: '#A94442',\r\n incentiveHeaderColor: '#3d6a3c',\r\n dropdownHoverColor: '#deebff',\r\n incentiveHeaderHoverColor: '#39a937',\r\n modalHeader: '#818181',\r\n carfaxBackground: '#3777bc',\r\n goodTireColor: '#406a3b',\r\n normalTireColor: '#e3c35e',\r\n badTireColor: '#ba0000',\r\n issueColor: '#b11926',\r\n defaultTextColor: '#000000',\r\n stickyTextColor: '#ffffff',\r\n darkGrayColor: '#606060',\r\n shadeGrayColor: '#333333',\r\n hoverConfirmButtonColor: '#a50129',\r\n\r\n loaderColor: 'secondary',\r\n\r\n //Cancel button colors\r\n cancelButtonBackgroundColor: '#606060',\r\n cancelButtonColor: '#ffffff',\r\n cancelButtonHoverBackgroundColor: '#333333',\r\n\r\n //Home Section Header\r\n homeSectionBackgroundColor: '#ffffff',\r\n homeSectionColor: '#000000',\r\n\r\n InfinitiOnlyColor: '#000000',\r\n\r\n hyperLinkColor: 'rgb(91, 46, 138)',\r\n hyperLinkHoverColor: 'rgb(155, 129, 252)',\r\n stepperCompleteColor: '#808080',\r\n\r\n InfinitiLinkColor: '#5b2e8a',\r\n InfinitiLinkHoverColor: '#9b81fc'\r\n },\r\n headerSticky: {\r\n text: '#494949',\r\n textHover: '#E6E6E6',\r\n backgroundColor: '#B0A591',\r\n spanUnderline: '#E6E6E6',\r\n subMenuBackground: '#B0A591',\r\n subMenuItemBorder: '#E6E6E6',\r\n subMenuItemHover: '#E6E6E6',\r\n userMenuFont: '#494949'\r\n },\r\n headerNotSticky: {\r\n text: '#000000',\r\n textHover: '#D4D4D4',\r\n spanUnderline: '#D4D4D4',\r\n subMenuBackground: '#ffffff',\r\n subMenuItemBorder: '#D4D4D4',\r\n subMenuItemHover: '#646464',\r\n userMenuFont: '#000000'\r\n },\r\n carousel: {\r\n buttonBackground: '#ffffff',\r\n buttonColor: '#000000',\r\n buttonBorder: '#000000',\r\n buttonHoverBackground: '#000000',\r\n buttonHoverBorderColor: '#000000'\r\n },\r\n footer: {\r\n backgroundColor: '#f5f5f5',\r\n fontColor: '#666'\r\n },\r\n logo: {\r\n left: 'vendor-main-logo.png',\r\n right: 'site_title-new.png?version=2'\r\n },\r\n fonts: {\r\n fontBase: 'Nissan AG Bold',\r\n fontRegular: 'NissanGroup Regular'\r\n }\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const NissanCustomStyle = styled.div``\r\n","import { DefaultTheme } from 'styled-components'\r\n\r\nexport const theme: DefaultTheme = {\r\n colors: {\r\n primary: '#c3002f',\r\n tableStriped: '#e9e9e9',\r\n tableBorder: '#dee2e6',\r\n footer: '#232323',\r\n primaryDarken: '#0e233e',\r\n secondary: '#E3E4E5',\r\n linkColor: '#4270d2',\r\n linkColorLight: '#0083c6',\r\n inputBorder: '#d4d4d4',\r\n fontColor: '#5b5b5b',\r\n inputBackgroundColor: '#ffffff',\r\n mobileMenuBackground: '#f4f4f4',\r\n sectionContentBackgroundColor: '#f6f6f6',\r\n borderInput: '1px solid #d4d4d4',\r\n infoColor: '#6a8c9c',\r\n successColor: '#26ad77',\r\n warningColor: '#f90',\r\n dangerColor: '#b11926',\r\n ribbonInfoBackgroundColor: '#dae2e6',\r\n ribbonSuccessBackgroundColor: '#c9eadd',\r\n ribbonWarningBackgroundColor: '#ffe5bf',\r\n ribbonDangerBackgroundColor: '#ebc5c9',\r\n backgroundText: 'white',\r\n colorTextModal: '#f2dede',\r\n colorButtonDisabled: '#444',\r\n switchBackgroundColor: '#6f6f6f',\r\n headerFontColor: '#494949',\r\n defaultDealerDeactive: '#A94442',\r\n incentiveHeaderColor: '#3d6a3c',\r\n dropdownHoverColor: '#deebff',\r\n incentiveHeaderHoverColor: '#39a937',\r\n modalHeader: '#818181',\r\n carfaxBackground: '#3777bc',\r\n goodTireColor: '#406a3b',\r\n normalTireColor: '#e3c35e',\r\n badTireColor: '#ba0000',\r\n issueColor: '#b11926',\r\n defaultTextColor: '#000000',\r\n stickyTextColor: '#ffffff',\r\n darkGrayColor: '#606060',\r\n shadeGrayColor: '#333333',\r\n hoverConfirmButtonColor: '#a50129',\r\n\r\n //Cancel button colors\r\n cancelButtonBackgroundColor: '#ffffff',\r\n cancelButtonColor: '#000000',\r\n cancelButtonHoverBackgroundColor: '#000000',\r\n\r\n //Home Section Header\r\n homeSectionBackgroundColor: '#000000',\r\n homeSectionColor: '#ffffff',\r\n\r\n InfinitiOnlyColor: '#c3002f',\r\n\r\n hyperLinkColor: 'rgb(195, 0, 47)',\r\n hyperLinkHoverColor: 'rgb(165, 1, 41)',\r\n stepperCompleteColor: '#e18097',\r\n InfinitiLinkColor: '#c3002f',\r\n InfinitiLinkHoverColor: '#a50129'\r\n },\r\n headerSticky: {\r\n text: '#E3E4E5',\r\n textHover: '#deebff',\r\n backgroundColor: '#c3002f',\r\n spanUnderline: '#deebff',\r\n subMenuBackground: '#c3002f',\r\n subMenuItemBorder: '#ffffff',\r\n subMenuItemHover: '#ffffff',\r\n userMenuFont: '#E3E4E5'\r\n },\r\n headerNotSticky: {\r\n text: '#000000',\r\n textHover: '#c3002f',\r\n spanUnderline: '#c3002f',\r\n subMenuBackground: '#ffffff',\r\n subMenuItemBorder: '#c3002f',\r\n subMenuItemHover: '#c3002f',\r\n userMenuFont: '#000000'\r\n },\r\n carousel: {\r\n buttonBackground: '#c3002f',\r\n buttonColor: '#ffffff',\r\n buttonBorder: '#c3002f',\r\n buttonHoverBackground: '#a50129',\r\n buttonHoverBorderColor: '#c3002f'\r\n },\r\n footer: {\r\n backgroundColor: '#232323',\r\n fontColor: '#fff'\r\n },\r\n logo: {\r\n left: 'vendor-main-logo.png',\r\n right: 'site_title-new.png?version=2'\r\n },\r\n fonts: {\r\n fontBase: 'Nissan AG Bold',\r\n fontRegular: 'NissanGroup Regular'\r\n }\r\n}\r\n","import { assetFolders } from 'common/constants'\r\nimport { GuestTheme } from 'core/skins/GUEST/theme'\r\nimport { IndependentTheme } from 'core/skins/INDEPENDENT/theme'\r\nimport { InfinitiTheme } from 'core/skins/INFINITI/theme'\r\nimport { NissanCustomStyle } from 'core/skins/NISSAN/custom'\r\nimport { theme } from 'core/skins/NISSAN/theme'\r\nimport { PropsWithChildren } from 'react'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { ThemeProvider, createGlobalStyle } from 'styled-components'\r\n\r\nconst GlobalStyle = createGlobalStyle`\r\n`\r\n\r\nexport const PortalThemeProvider = ({ children }: PropsWithChildren) => {\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n\r\n const getTheme = () => {\r\n switch (assetFolder) {\r\n case assetFolders.Infiniti:\r\n return InfinitiTheme\r\n case assetFolders.Nissan:\r\n return theme\r\n case assetFolders.Independent:\r\n return IndependentTheme\r\n default:\r\n return GuestTheme\r\n }\r\n }\r\n return (\r\n \r\n \r\n {children}\r\n \r\n )\r\n}\r\n","import { useEffect } from 'react'\r\nimport { useSignalRStore } from 'store/useSignalRStore'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\n\r\nconst useNotification = () => {\r\n const { connectionID, connect, subscribe, susbcribeEvents } = useSignalRStore((state) => state)\r\n const { getBaseVehicle } = useVehicleStore((state) => state)\r\n const vehicleIds = useVehicleStore((state) => state.vehicles.map((item) => item.vehicle.InstanceID))\r\n useEffect(() => {\r\n connect()\r\n susbcribeEvents()\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!connectionID) {\r\n return\r\n }\r\n\r\n subscribe(vehicleIds)\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [connectionID])\r\n\r\n useEffect(() => {\r\n async function subscribeUpdateVehicle() {\r\n try {\r\n $.connection.notificationHub.off('updateVehicle').on('updateVehicle', getBaseVehicle)\r\n } catch (error) {\r\n console.error('SignalR: Error trying to subscribe to notification hub')\r\n }\r\n }\r\n\r\n if (connectionID) {\r\n subscribeUpdateVehicle()\r\n }\r\n\r\n return () => {\r\n $.connection.notificationHub.off('updateVehicle')\r\n }\r\n // We use dispatch so the callback is always a constant, so we don't need to watch for changes\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [connectionID])\r\n}\r\n\r\nexport default useNotification\r\n","import { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const HeaderStyled = styled(Modal.Header)`\r\n font-size: 1.6rem;\r\n`\r\n","import { Modal } from 'react-bootstrap'\r\nimport { HeaderStyled } from './LinkNameModal.styled'\r\n\r\ninterface ILinkNameModal {\r\n show: boolean\r\n handleClose: () => void\r\n bodyText: string\r\n}\r\n\r\nexport const LinkNameModal = ({ show, handleClose, bodyText }: ILinkNameModal) => {\r\n return (\r\n <>\r\n \r\n {bodyText}\r\n \r\n >\r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledBreadCrumbICon = styled.span`\r\n margin-left: 0.5rem;\r\n margin-right: 0.5rem;\r\n\r\n &:first-child {\r\n margin-left: 0;\r\n }\r\n`\r\n\r\nexport const StyledBreadCrumbMenu = styled.div`\r\n display: flex;\r\n margin-bottom: 2.5rem;\r\n align-items: self-end;\r\n\r\n a {\r\n font-size: 1.4rem;\r\n }\r\n`\r\n","import { faChevronRight, faHome } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { Fragment, PropsWithChildren, useMemo } from 'react'\r\nimport { Link, useRouteMatch } from 'react-router-dom'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IMenuInfo } from 'types/userTypes'\r\nimport { findMenuParent } from 'utils/menuUtils'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledBreadCrumbICon, StyledBreadCrumbMenu } from './BreadcrumbMenu.styled'\r\n\r\nexport const menus: IMenuInfo[] = [\r\n { path: '/terms', text: 'Terms and Condition', description: 'Terms and Condition' },\r\n { path: '/privacy', text: 'Privacy Policy', description: 'Privacy Policy' },\r\n { path: '/contactUs', text: 'Contact Us', description: 'Contact Us' },\r\n { path: '/faqs', text: 'Frequently Asked Questions', description: 'Frequently Asked Questions' }\r\n]\r\n\r\nexport const BreadcrumbMenu = ({ children }: PropsWithChildren) => {\r\n const routematch = useRouteMatch()\r\n const breadcrumbs = findMenuParent(menus, routematch.path)\r\n const userClaims = useGlobalStore((state) => state.userClaims, shallow)\r\n const isShow = useMemo(\r\n () => ((userClaims.IsTermAccepted && userClaims.Username) || !userClaims.Username ? true : false),\r\n [userClaims.Username, userClaims.IsTermAccepted]\r\n )\r\n\r\n return (\r\n <>\r\n {isShow && (\r\n \r\n \r\n \r\n \r\n \r\n \r\n {breadcrumbs?.map((item, index) => (\r\n \r\n \r\n \r\n \r\n {item.path ? {item.text} : {item.text}}\r\n \r\n ))}\r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport { Button, Form } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const Title = styled.h2`\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-size: 3rem;\r\n margin-bottom: 1.2rem;\r\n`\r\n\r\nexport const ContactHeader = styled.h4`\r\n color: ${({ theme }) => theme.colors.primary};\r\n text-transform: uppercase;\r\n margin-bottom: 1.2rem;\r\n width: inherit;\r\n text-align: center;\r\n`\r\nexport const ContactBody = styled.p`\r\n font-size: 1.6rem;\r\n`\r\n\r\nexport const ContactUsBody = styled.div`\r\n background-color: ${({ theme }) => theme.colors.backgroundText};\r\n margin-left: 2.4rem;\r\n margin-right: 2.4rem;\r\n margin-bottom: 2.4rem;\r\n flex: 1;\r\n\r\n .alert {\r\n width: 100%;\r\n p {\r\n margin-bottom: 0;\r\n }\r\n button {\r\n width: 5rem;\r\n }\r\n }\r\n\r\n textarea {\r\n resize: none;\r\n }\r\n`\r\n\r\nexport const FormContainer = styled.div`\r\n flex-direction: column;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n\r\n .custom-select {\r\n background: none;\r\n }\r\n\r\n .custom-select-lg {\r\n height: calc(1.5em + 0.75rem + 0.2rem);\r\n padding: 0.375rem 0.75rem;\r\n font-size: 1.3rem;\r\n }\r\n`\r\n\r\nexport const FormBody = styled.div`\r\n width: 100%;\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n font-size: 1.4rem;\r\n\r\n a {\r\n display: inline-block;\r\n }\r\n\r\n button {\r\n display: inline-block;\r\n width: 10rem;\r\n margin-top: 0;\r\n }\r\n\r\n .was-validated .form-control:valid,\r\n .custom-select:valid,\r\n .custom-select.is-valid .form-control.is-valid {\r\n border-color: #ced4da;\r\n background-image: none;\r\n }\r\n\r\n .was-validated .custom-select:invalid,\r\n .custom-select.is-invalid {\r\n background: none;\r\n }\r\n`\r\n\r\nexport const GroupButtonStyled = styled(Form.Group)`\r\n float: right;\r\n`\r\n\r\nexport const SubmitButton = styled(Button)`\r\n height: 3rem;\r\n font-size: 1.4rem;\r\n width: 100%;\r\n margin-top: 1rem;\r\n line-height: 0.5;\r\n`\r\n\r\nexport const CancelButton = styled.div`\r\n margin-top: auto;\r\n margin-right: 2rem;\r\n display: inline-block;\r\n vertical-align: bottom;\r\n`\r\n\r\nexport const LinkNameStyled = styled(Form.Group)`\r\n color: ${({ theme }) => theme.colors.primary};\r\n text-align: center;\r\n font-size: 1.4rem;\r\n font-weight: 500;\r\n margin: auto;\r\n margin-top: 3rem;\r\n\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n margin-top: 0;\r\n }\r\n`\r\n\r\nexport const LinkNameText = styled.a`\r\n float: left;\r\n`\r\n","import { getContactUsDropDown, getValidatedVin, sendContactUsEmail } from 'apis/userApis'\r\nimport { MultiLanguageCode } from 'common/languageCodes'\r\nimport { LinkNameModal } from 'modules/ContactUs/LinkNameModal'\r\nimport { HTMLText } from 'components/Share/HtmlText'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport parse from 'html-react-parser'\r\nimport { BreadcrumbMenu } from 'layouts/BreadcrumbMenu'\r\nimport { Layout } from 'layouts/Layout'\r\nimport { LinkBaseStyled } from 'layouts/LoginLayout.styled'\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport { Alert, Col, Form, Row } from 'react-bootstrap'\r\nimport { FormattedMessage, useIntl } from 'react-intl'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { IContactReason, IContactUsData } from 'types/contactTypes'\r\nimport { validateVin } from 'utils/utils'\r\nimport shallow from 'zustand/shallow'\r\nimport {\r\n CancelButton,\r\n ContactBody,\r\n ContactHeader,\r\n ContactUsBody,\r\n FormBody,\r\n FormContainer,\r\n GroupButtonStyled,\r\n LinkNameStyled,\r\n LinkNameText,\r\n SubmitButton,\r\n Title\r\n} from './ContactUs.styled'\r\n\r\ninterface IAlertData {\r\n textAlert: string\r\n result: boolean\r\n isDisplay: boolean\r\n}\r\n\r\nexport const ContactUs = () => {\r\n const { data: contactReasons } = useFetch(() => getContactUsDropDown(vendor?.ID))\r\n const intl = useIntl()\r\n const [validated, setValidated] = useState(false)\r\n const [contactReasonOptions, setContactReasonOptions] = useState([])\r\n const [contactReason, setContactReason] = useState()\r\n const [userClaims, getLocalText, vendor] = useGlobalStore(\r\n (state) => [state.userClaims, state.getLocalText, state.vendor],\r\n shallow\r\n )\r\n const [displayVin, setDisplayVin] = useState(false)\r\n const [linkName, setLinkName] = useState('')\r\n const [linkText, setLinkText] = useState('')\r\n const [showModal, setShowModal] = useState(false)\r\n const handleClose = () => setShowModal(false)\r\n const handleShow = () => setShowModal(true)\r\n const [alertModel, setAlertModel] = useState({ result: false, textAlert: '', isDisplay: false })\r\n const vinRef = useRef()\r\n const { endPageLoad } = useDtmAnalytics()\r\n\r\n useEffect(() => {\r\n setContactReasonOptions(contactReasons?.ContactReasons)\r\n endPageLoad()\r\n }, [contactReasons])\r\n\r\n const handleSubmit = async (event) => {\r\n event.preventDefault()\r\n let vinDomElement = vinRef.current as any\r\n setValidated(true)\r\n const form = event.currentTarget\r\n const isValidVin = !contactReason?.IsArbitrate || (await checkVinValidity(vinDomElement))\r\n if (form.checkValidity() && isValidVin) {\r\n let request: IContactUsData = {\r\n contactReason: contactReason,\r\n firstName: form.firstName.value,\r\n lastName: form.lastName.value,\r\n email: form.email.value,\r\n phone: form.phone?.value,\r\n company: form.company?.value,\r\n message: form.message.value,\r\n vin: form.Vin?.value,\r\n vendorId: vendor?.ID\r\n }\r\n\r\n const result = await sendContactUsEmail(request)\r\n\r\n if (result) {\r\n setAlertModel({ result, textAlert: getLocalText('CONTACTUS_SUCCESS', 'CONTACTUS_SUCCESS'), isDisplay: true })\r\n } else {\r\n let data: IAlertData = {\r\n result: false,\r\n textAlert: getLocalText('EMAIL_FAILED', 'EMAIL_FAILED'),\r\n isDisplay: true\r\n }\r\n setAlertModel(data)\r\n }\r\n resetFormField(form)\r\n }\r\n return\r\n }\r\n\r\n const selectOptionChange = (e: any) => {\r\n let data = contactReasonOptions.find((x) => x.Reason === e.target.value)\r\n setContactReason(data)\r\n setLinkName(data?.LinkName)\r\n setLinkText(data?.LinkText)\r\n setDisplayVin(data?.IsArbitrate ? true : false)\r\n }\r\n\r\n const checkVinValidity = async (el: any) => {\r\n let vin = el?.value\r\n let isValid = false\r\n\r\n if (validateVin(vin)) {\r\n isValid = await getValidatedVin(vendor.ID, vin)\r\n }\r\n\r\n if (isValid) {\r\n el.setCustomValidity('')\r\n } else {\r\n el.setCustomValidity('invalid')\r\n }\r\n return isValid\r\n }\r\n\r\n const vinOnChange = async () => {\r\n let vinDomElement = vinRef.current as any\r\n if (validated && vinDomElement) {\r\n const isValidVin = await checkVinValidity(vinDomElement)\r\n }\r\n\r\n return\r\n }\r\n\r\n const resetFormField = (form: any) => {\r\n setValidated(false)\r\n\r\n form.firstName.value = ''\r\n form.lastName.value = ''\r\n form.email.value = ''\r\n form.phone.value = ''\r\n form.company.value = ''\r\n form.message.value = ''\r\n setContactReason({ ...contactReason, Reason: '' })\r\n\r\n if (contactReason?.IsArbitrate) {\r\n form.Vin.value = ''\r\n }\r\n }\r\n return (\r\n \r\n {showModal && }\r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n\r\n \r\n \r\n \r\n {alertModel?.isDisplay && (\r\n setAlertModel({ ...alertModel, isDisplay: false })}\r\n dismissible\r\n >\r\n {alertModel?.textAlert}
\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n Contact Reason\r\n selectOptionChange(e)}\r\n value={contactReason?.Reason}\r\n required\r\n >\r\n {contactReasonOptions?.map((option) => {\r\n return (\r\n \r\n )\r\n })}\r\n \r\n \r\n {linkName && (\r\n \r\n {linkName}\r\n \r\n )}\r\n \r\n \r\n \r\n First Name*\r\n \r\n Please enter a first name\r\n \r\n\r\n \r\n Last Name*\r\n \r\n Please enter a last name\r\n \r\n \r\n \r\n \r\n Email*\r\n \r\n Please enter an email\r\n \r\n \r\n Company\r\n \r\n \r\n \r\n \r\n {displayVin && (\r\n \r\n VIN*\r\n \r\n Please enter a Vin\r\n \r\n )}\r\n\r\n \r\n Phone Number\r\n \r\n \r\n \r\n \r\n \r\n Message*\r\n \r\n Please enter a message\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\nimport { Popover } from 'react-bootstrap'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport { assetFolders } from 'common/constants'\r\n\r\nexport const StyledHomeSlideShow = styled.div<{ assetFolder?: string }>`\r\n margin: 0 auto;\r\n\r\n .carousel-item:not(.active) {\r\n .carousel-caption {\r\n opacity: 0;\r\n }\r\n }\r\n\r\n .carousel-item {\r\n img {\r\n aspect-ratio: 4/1;\r\n object-fit: cover;\r\n object-position: center;\r\n margin: auto;\r\n animation: skeleton-loading 1s linear infinite alternate;\r\n }\r\n img.clickable {\r\n cursor: pointer;\r\n }\r\n @keyframes skeleton-loading {\r\n 0% {\r\n background: rgba(0, 0, 0, 0.1);\r\n }\r\n 100% {\r\n background: rgba(0, 0, 0, 0.4);\r\n }\r\n }\r\n }\r\n\r\n .carousel-inner {\r\n overflow: visible;\r\n }\r\n .carousel-control-next-icon,\r\n .carousel-control-prev-icon {\r\n background: none;\r\n height: unset;\r\n width: unset;\r\n }\r\n .carousel-control-prev {\r\n left: -4.4rem;\r\n width: 0;\r\n }\r\n .carousel-control-next {\r\n right: -4.4rem;\r\n width: 0;\r\n }\r\n .carousel-control-next-icon::after {\r\n content: '›';\r\n font-size: 7rem;\r\n font-weight: 500;\r\n color: #0070d2;\r\n }\r\n .carousel-control-prev-icon::before {\r\n content: '‹';\r\n font-size: 7rem;\r\n font-weight: 500;\r\n color: #0070d2;\r\n }\r\n .carousel-indicators {\r\n bottom: 0;\r\n }\r\n .carousel-indicators li {\r\n background-color: #808080;\r\n width: 4rem;\r\n border-radius: 0.2rem / 1.2rem;\r\n }\r\n .carousel-indicators .active {\r\n background-color: ${({ theme, assetFolder }) =>\r\n assetFolder === assetFolders.Infiniti ? theme.colors.defaultTextColor : theme.colors.primary};\r\n }\r\n .carousel-caption {\r\n position: initial;\r\n font-size: 1.6rem;\r\n }\r\n`\r\nexport const StyledPromotion = styled.div`\r\n display: flex;\r\n position: relative;\r\n bottom: -4.5rem;\r\n color: #101010;\r\n font-weight: bold;\r\n text-transform: uppercase;\r\n padding: 0 2.4rem;\r\n padding-bottom: 2rem;\r\n justify-content: center;\r\n align-items: center;\r\n span {\r\n /* word-wrap: break-word; */\r\n overflow: hidden;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 1;\r\n -webkit-box-orient: vertical;\r\n max-width: 50%;\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n flex-direction: column;\r\n span {\r\n width: 100%;\r\n max-width: 60%;\r\n }\r\n }\r\n`\r\nexport const StyledSearch = styled.div`\r\n width: 11rem;\r\n font-size: 1.4rem;\r\n margin-left: 1rem;\r\n`\r\n\r\nexport const PopoverContainer = styled(Popover)`\r\n position: absolute;\r\n top: 40px;\r\n font-size: small;\r\n left: 0px;\r\n display: block;\r\n width: fit-content;\r\n background-color: white;\r\n padding: 5px;\r\n border-radius: 0.4rem;\r\n text-overflow: ellipsis;\r\n max-width: 45ch;\r\n`\r\n","import { Button, Carousel, OverlayTrigger, Popover, Tooltip } from 'react-bootstrap'\r\nimport { LazyLoadImage } from 'react-lazy-load-image-component'\r\nimport { AdvertType, CarouselImage } from '../../types/baseTypes'\r\nimport { PopoverContainer, StyledHomeSlideShow, StyledPromotion, StyledSearch } from './SlideShow.styled'\r\nimport { Loader } from 'components/Loader'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { saveAs } from 'file-saver'\r\nimport { getCarouselImages } from 'apis/dashboardApis'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\n\r\nexport const SlideShow = () => {\r\n const { loading, data } = useFetch(() => getCarouselImages())\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n\r\n const clickHandler = (e: React.MouseEvent, item: CarouselImage) => {\r\n e.preventDefault()\r\n if (item.AdvertType === AdvertType.PictureOnly) return\r\n if (item.DocumentURL) saveAs(item.DocumentURL, item.DocumentName)\r\n }\r\n\r\n return (\r\n \r\n 1}>\r\n {!loading ? (\r\n data?.map((item, index) => (\r\n \r\n }\r\n onClick={(e) => clickHandler(e, item)}\r\n className={`d-block w-100 h-100 ${item.AdvertType !== AdvertType.PictureOnly && 'clickable'}`}\r\n src={item.ImageURL}\r\n />\r\n \r\n {item.AdvertType !== AdvertType.PictureOnly && (\r\n \r\n {item.Description}}\r\n >\r\n {item.Description}\r\n \r\n clickHandler(e, item)}>\r\n \r\n \r\n \r\n )}\r\n \r\n \r\n ))\r\n ) : (\r\n \r\n
\r\n \r\n \r\n )}\r\n \r\n \r\n )\r\n}\r\n","import { Popover, Row } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\nexport const StyledModelFigureCaption = styled.p`\r\n font-size: 1.8rem;\r\n font-weight: 600;\r\n text-align: center;\r\n width: 100%;\r\n color: ${({ theme }) => theme.colors.fontColor};\r\n\r\n & a {\r\n display: contents;\r\n font-size: 1.8rem;\r\n font-weight: 600;\r\n margin-left: 0.5rem;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n\r\n &:focus,\r\n &.focus {\r\n box-shadow: none;\r\n text-decoration: none;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledModelFigure = styled(Row).attrs(({ className }) => ({\r\n className: `h-100 ${className ?? ''}`.trim()\r\n}))`\r\n display: flex;\r\n justify-content: center;\r\n\r\n & > .col {\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n\r\n img {\r\n object-fit: contain;\r\n /*\r\n * Make size a little bit smaller to prevent overlap\r\n * to siblings\r\n */\r\n width: 90%;\r\n }\r\n`\r\n\r\nexport const StyledPopover = styled(Popover)`\r\n box-shadow: 0 0.2rem 0.5rem rgb(0 0 0 / 25%);\r\n z-index: 1000;\r\n .car-tooltip-header {\r\n margin-bottom: 1rem;\r\n\r\n .model-type {\r\n margin-top: -0.75rem;\r\n font-size: 1.6rem;\r\n }\r\n }\r\n\r\n .car-tooltip-header span {\r\n display: block;\r\n }\r\n\r\n .popover-body {\r\n font-size: 1.4rem;\r\n }\r\n`\r\n\r\nexport const BodyStyled = styled.div`\r\n display: grid;\r\n grid-template-columns: auto auto auto;\r\n gap: 1.25rem;\r\n\r\n div > span {\r\n a {\r\n font-size: 1.4rem;\r\n display: contents;\r\n padding: 0;\r\n margin: 0;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n\r\n display: contents;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n`\r\n","import { useEffect, useState } from 'react'\r\nimport { Button, Col, OverlayTrigger, Popover, Row } from 'react-bootstrap'\r\nimport Image from 'react-bootstrap/Image'\r\nimport { IModelFigure, IModelYear } from '../../types/IModelFigure'\r\nimport { BodyStyled, StyledModelFigure, StyledModelFigureCaption, StyledPopover } from './ModelFigure.styled'\r\nimport { vendorImages } from 'common/constants'\r\n\r\nexport const ModelFigure = ({ imageUrl, modelType, make, onRedirect, total, ...props }: IModelFigure) => {\r\n const [yearFilter, setYearFilter] = useState()\r\n const [showtooltip, setShowtooltip] = useState(false)\r\n\r\n useEffect(() => {\r\n setYearFilter(props.modelYears)\r\n }, [props.modelYears])\r\n\r\n return (\r\n \r\n \r\n setShowtooltip(true)}\r\n onMouseLeave={() => setShowtooltip(false)}\r\n >\r\n 0}\r\n overlay={\r\n \r\n setShowtooltip(true)} onMouseLeave={() => setShowtooltip(false)}>\r\n \r\n {make}\r\n \r\n {modelType}\r\n \r\n
\r\n \r\n {yearFilter?.map((yearModel, index) => (\r\n \r\n {yearModel.year} \r\n \r\n \r\n \r\n
\r\n ))}\r\n \r\n \r\n \r\n }\r\n >\r\n {imageUrl ? : }\r\n \r\n
\r\n \r\n {modelType} \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledCountingText = styled.span<{ assetFolder?: string }>`\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n font-weight: 600;\r\n`\r\n","import { getDashboardGrounding } from 'apis/dashboardApis'\r\nimport { quickSearch } from 'apis/vehicleApis'\r\nimport { AVAILABLE_INVENTORY_INIT_QUERY } from 'common/constants'\r\nimport { IDashboardVehicles, ISearchFilterResult } from 'types/vehicleTypes'\r\nimport create from 'zustand'\r\nimport { useGlobalStore } from './useGlobalStore'\r\nimport { Rules } from 'common/rules'\r\n\r\nexport interface IDashBoardDataState {\r\n groundingData: IDashboardVehicles\r\n fetchGroundingData: () => Promise\r\n filters: ISearchFilterResult[]\r\n totalVehicles: number\r\n fetchFilters: () => Promise\r\n}\r\n\r\nexport const useDashboardStore = create((set, get) => ({\r\n groundingData: {} as IDashboardVehicles,\r\n\r\n fetchGroundingData: async () => {\r\n if (useGlobalStore.getState().isInRule(Rules.VIEW_GROUNDING_ACTIVITY)) {\r\n const resp = await getDashboardGrounding()\r\n if (resp) {\r\n set((state) => ({ ...state, groundingData: resp }))\r\n }\r\n }\r\n },\r\n filters: [],\r\n totalVehicles: 0,\r\n\r\n fetchFilters: async () => {\r\n const allowRules = [Rules.PAGE_RDP_SRP, Rules.VIEW_ADVANCED_SEARCH_PAGE]\r\n if (allowRules?.some((rule) => useGlobalStore.getState().isInRule(rule))) {\r\n const resp = await quickSearch({ ...AVAILABLE_INVENTORY_INIT_QUERY })\r\n\r\n if (resp) {\r\n set((state) => ({\r\n ...state,\r\n filters: [...resp.Data] as ISearchFilterResult[],\r\n totalVehicles: resp.TotalRecords\r\n }))\r\n return\r\n }\r\n }\r\n set((state) => ({\r\n ...state,\r\n filters: [] as ISearchFilterResult[],\r\n totalVehicles: 0\r\n }))\r\n }\r\n}))\r\n","import { IModelGroupImages } from 'types/IModelFigure'\r\nimport { BodyStyles, IVehicleSearchDocument } from 'types/vehicleTypes'\r\nimport { MODEL_GROUP_MAPPER } from 'common/constants'\r\nimport { uniq } from 'lodash'\r\n\r\nexport const findModelGroupImage = (\r\n modelGroupImages: IModelGroupImages[],\r\n modelGroup: string,\r\n bodyStyle?: string,\r\n fuelType?: string\r\n) => {\r\n var groupImages = modelGroupImages?.filter((image) => image.ModelGroup === modelGroup)\r\n if (!groupImages?.length) {\r\n return\r\n }\r\n\r\n let match: IModelGroupImages\r\n\r\n if (fuelType) {\r\n match = groupImages.find(\r\n (image) =>\r\n image.FuelType ===\r\n (MODEL_GROUP_MAPPER.find((m) => m.DisplayText.toLowerCase() === fuelType.toLowerCase())?.Value ?? fuelType)\r\n )\r\n }\r\n\r\n if (!match && bodyStyle) {\r\n match = groupImages.find(\r\n (image) =>\r\n image.BodyStyle ===\r\n (MODEL_GROUP_MAPPER.find((m) => m.DisplayText.toLowerCase() === bodyStyle.toLowerCase())?.Value ?? bodyStyle)\r\n )\r\n }\r\n\r\n if (!match) {\r\n // Default to Sedan if not found, or return first image of the group\r\n match = groupImages.find((image) => image.BodyStyle === BodyStyles.Sedan) || groupImages[0]\r\n }\r\n\r\n return match?.ImageURL\r\n}\r\n\r\nexport const getSeriesBasedOnModelGroup = (\r\n modelGroupFilters: [string, IVehicleSearchDocument[]][],\r\n modelGroupName: string\r\n) => {\r\n const filter = modelGroupFilters.find(([modelGroup, _]) => modelGroup === modelGroupName)\r\n if (!filter) return []\r\n\r\n return uniq((filter[1] as IVehicleSearchDocument[]).map((d) => d.Series))\r\n}\r\n","import { getModelGroupImages } from 'apis/dashboardApis'\r\nimport { searchAvailableInventory } from 'apis/vehicleApis'\r\nimport {\r\n AVAILABLE_INVENTORY_HEADING,\r\n AVAILABLE_INVENTORY_INIT_QUERY,\r\n AVAILABLE_INVENTORY_MAPPER,\r\n GENERIC_NO_VEHICLE_AVAILABLE_MESSAGE,\r\n SessionStorageKey\r\n} from 'common/constants'\r\nimport {\r\n isAnyChilrenFiltersSelected,\r\n processVehicleSearchDocumentResult,\r\n resetChildrenFilters,\r\n selectChildrenFilter\r\n} from 'common/helpers'\r\nimport Collapse from 'components/Collapse'\r\nimport {\r\n StyledHomeSection,\r\n StyledHomeSectionBody,\r\n StyledHomeSectionHeaderActionSection,\r\n StyledHomeSectionHeaderLink,\r\n StyledRowInventory\r\n} from 'components/Header/HomeSectionHeader.styled'\r\nimport { ModelFigure } from 'components/ModelFigure/ModelFigure'\r\nimport { useExpand } from 'hooks/useExpand'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { chain, cloneDeep, isEmpty, keyBy, merge, values } from 'lodash'\r\nimport { StyledCountingText } from 'modules/AvailableInventory.styled'\r\nimport { useEffect, useMemo, useReducer, useState } from 'react'\r\nimport { Col, Row } from 'react-bootstrap'\r\nimport { ISearchFilterResult, IVehicleSearchDocument } from 'types/vehicleTypes'\r\nimport { HomeSectionHeader } from '../components/Header/HomeSectionHeader'\r\n\r\nimport { faCar } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { isReactRoutes } from 'common/routes'\r\nimport { srpFilters } from 'common/srpFilters'\r\nimport { Loader } from 'components/Loader'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { DtmComponentName, getInventoryClickName } from 'utils/analyticsUtils'\r\nimport { resetSRPFilter } from 'utils/menuUtils'\r\nimport { findModelGroupImage, getSeriesBasedOnModelGroup } from 'utils/modelGroupUtils'\r\nimport { getSearchUrl } from 'utils/urlUtils'\r\nimport shallow from 'zustand/shallow'\r\nimport { Rules } from 'common/rules'\r\n\r\ninterface IFiltersReducerAction {\r\n type: 'INIT' | 'UPDATE' | 'RESET_ALL'\r\n payload?: ISearchFilterResult[]\r\n}\r\n\r\nconst filterEmptyResultSearchFilters = (filters: Record, ContentData: IVehicleSearchDocument[]) => {\r\n Object.entries(filters).forEach(([key, values]) => {\r\n filters[key] = [\r\n ...values.filter((v) => {\r\n // 1. Get original value (if have)\r\n const splittedValues = (AVAILABLE_INVENTORY_MAPPER.find((m) => m.DisplayText === v)?.Value ?? v).split(',')\r\n\r\n // 2. Filters from ContentData to check if we have any items\r\n return splittedValues.some((v) => ContentData.some((d) => d[key] === v))\r\n })\r\n ]\r\n })\r\n\r\n return filters\r\n}\r\n\r\nconst filtersReducer = (state: ISearchFilterResult[], action: IFiltersReducerAction): ISearchFilterResult[] => {\r\n switch (action.type) {\r\n case 'INIT':\r\n const initFilters = cloneDeep([...action.payload]) as ISearchFilterResult[]\r\n return initFilters\r\n case 'UPDATE':\r\n return values(merge(keyBy(state, 'DBFieldName'), keyBy(action.payload, 'DBFieldName')))\r\n case 'RESET_ALL':\r\n resetChildrenFilters(state)\r\n return state\r\n default:\r\n return state\r\n }\r\n}\r\n\r\ninterface IProps {\r\n isFilterLoading: boolean\r\n}\r\n\r\nexport const AvailableInventory = ({ isFilterLoading: HeadingLoading }: IProps) => {\r\n const { state: expandState, action: expandAction } = useExpand({ componentOpen: true } as never)\r\n const [displayFilters, setDisplayFilters] = useState(() => AVAILABLE_INVENTORY_HEADING)\r\n const [isViewAllClicked, setIsViewAllClicked] = useState(true)\r\n const [filters, dispatchFilters] = useReducer(filtersReducer, null)\r\n const [currentFuelType, setCurrentFuelType] = useState('')\r\n const [currentBodyStyle, setCurrentBodyStyle] = useState(null)\r\n const history = useHistory()\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n\r\n const { data: modelGroupImages = [] } = useFetch(() => getModelGroupImages())\r\n\r\n const { filters: HeadingData, totalVehicles: TotalRecords } = useDashboardStore((state) => state, shallow)\r\n\r\n const { loading: ContentLoading, data: ContentData } = useFetch(\r\n () => searchAvailableInventory({ ...AVAILABLE_INVENTORY_INIT_QUERY }),\r\n [Rules.PAGE_RDP_SRP, Rules.VIEW_ADVANCED_SEARCH_PAGE]\r\n )\r\n\r\n const { componentOpen } = expandState\r\n const { setExpand } = expandAction\r\n const { userInteraction, endComponentLoad } = useDtmAnalytics()\r\n\r\n useEffect(() => {\r\n if (!ContentLoading) {\r\n endComponentLoad(DtmComponentName.DashboardInventory)\r\n }\r\n }, [ContentLoading, endComponentLoad])\r\n\r\n // Set default filters\r\n useEffect(() => {\r\n if (HeadingLoading || !HeadingData) return\r\n\r\n const payload = [...HeadingData] as ISearchFilterResult[]\r\n\r\n dispatchFilters({ type: 'INIT', payload: payload })\r\n }, [HeadingLoading, HeadingData])\r\n\r\n // Use to update filters show on UI\r\n useEffect(() => {\r\n if (ContentLoading || !ContentData) return\r\n\r\n setDisplayFilters((ft) => ({ ...filterEmptyResultSearchFilters(ft, ContentData) }))\r\n }, [ContentLoading, ContentData])\r\n\r\n const bodyStyleFilters = useMemo(() => filters?.find((item) => item.FieldName === srpFilters.BodyStyle), [filters])\r\n const makeFilters = useMemo(() => filters?.find((item) => item.FieldName === srpFilters.Make), [filters])\r\n\r\n const modelGroupFilters = useMemo(() => {\r\n if (!filters || !ContentData) return\r\n\r\n let result = [...ContentData]\r\n\r\n // Filters for Available Inventory View\r\n\r\n // 1. Check 'Body Style' filter\r\n result = processVehicleSearchDocumentResult(result, filters, srpFilters.BodyStyle, (r) => r.BodyStyle)\r\n\r\n // 2. Check 'Make' filter\r\n result = processVehicleSearchDocumentResult(result, filters, srpFilters.Make, (r) => r.Make)\r\n\r\n // 3. Check 'Fuel Type' filter\r\n if (currentFuelType !== '') {\r\n if (isAnyChilrenFiltersSelected(filters, srpFilters.FuelType)) {\r\n result = processVehicleSearchDocumentResult(result, filters, srpFilters.FuelType, (r) => r.FuelType)\r\n } else {\r\n // Remove all results as we don't have any filters match selected fuel type\r\n // This will make the list empty and the UI will render 'No vehicle available' message\r\n result = []\r\n }\r\n }\r\n\r\n // 4. Transform & Return result\r\n return Object.entries(chain(result).orderBy('ModelGroup').groupBy('ModelGroup').value())\r\n }, [ContentData, currentFuelType, filters])\r\n\r\n const handleChangeBodyStyleFilters = (bodyStyle: string) => {\r\n // Reset flag for Fuel Type\r\n setCurrentFuelType('')\r\n setIsViewAllClicked(false)\r\n resetChildrenFilters(filters)\r\n\r\n const originalValues = AVAILABLE_INVENTORY_MAPPER.find((m) => m.DisplayText === bodyStyle)?.Value?.split(',')\r\n if (\r\n originalValues &&\r\n originalValues.some((value) =>\r\n filters.find((q) => q.FieldName === srpFilters.BodyStyle)?.ChildrenFilter?.some((cft) => cft.Value === value)\r\n )\r\n ) {\r\n selectChildrenFilter(filters, srpFilters.BodyStyle, ...originalValues)\r\n } else {\r\n selectChildrenFilter(filters, srpFilters.BodyStyle, bodyStyle)\r\n }\r\n\r\n selectChildrenFilter(filters, srpFilters.BodyStyle, bodyStyle)\r\n setCurrentBodyStyle(bodyStyle)\r\n\r\n dispatchFilters({ type: 'UPDATE', payload: filters })\r\n userInteraction(`Available Inventory: ${bodyStyle}`)\r\n }\r\n\r\n const handleChangeFuelTypeFilters = (fuelType: string) => {\r\n // 0. Reset values\r\n resetChildrenFilters(filters)\r\n setCurrentBodyStyle(null)\r\n setIsViewAllClicked(false)\r\n\r\n // 1. Convert value to original value (using MAPPER)\r\n const originalFuelTypes = AVAILABLE_INVENTORY_MAPPER.find((m) => m.DisplayText === fuelType)?.Value?.split(',')\r\n\r\n // 2. If Update query with selected fuel types\r\n if (\r\n originalFuelTypes &&\r\n originalFuelTypes.some((value) =>\r\n filters.find((q) => q.FieldName === srpFilters.FuelType)?.ChildrenFilter?.some((cft) => cft.Value === value)\r\n )\r\n ) {\r\n selectChildrenFilter(filters, srpFilters.FuelType, ...originalFuelTypes)\r\n } else {\r\n selectChildrenFilter(filters, srpFilters.FuelType, fuelType)\r\n }\r\n\r\n dispatchFilters({ type: 'UPDATE', payload: filters })\r\n\r\n // Set Fuel Type flag\r\n setCurrentFuelType(fuelType)\r\n userInteraction(`Available Inventory: ${fuelType}`)\r\n }\r\n\r\n const handleChangeMakeFilters = (make: string) => {\r\n // Reset flag for Fuel Type\r\n setCurrentFuelType('')\r\n setCurrentBodyStyle(null)\r\n setIsViewAllClicked(false)\r\n resetChildrenFilters(filters)\r\n selectChildrenFilter(filters, srpFilters.Make, make)\r\n\r\n dispatchFilters({ type: 'UPDATE', payload: filters })\r\n }\r\n\r\n const handleRedirect = (ft?: ISearchFilterResult[]) => {\r\n resetSRPFilter()\r\n sessionStorage.setItem(SessionStorageKey.SEARCH_FILTERS, ft ? JSON.stringify(ft) : null)\r\n const customClickName = `Dashboard:${getInventoryClickName(ft)}`\r\n userInteraction(customClickName)\r\n\r\n if (isReactRoutes(getSearchUrl())) history.push(getSearchUrl(), ft)\r\n else window.location.href = getSearchUrl()\r\n }\r\n\r\n const handleFilterViewAllVehicles = () => {\r\n setIsViewAllClicked(true)\r\n setCurrentBodyStyle(null)\r\n setCurrentFuelType('') // Reset flag for Fuel Type\r\n const payload = [...HeadingData] as ISearchFilterResult[]\r\n dispatchFilters({ type: 'INIT', payload: payload })\r\n }\r\n\r\n const handleViewAllVehicles = () => {\r\n handleRedirect(null)\r\n }\r\n\r\n const handleRedirectModelGroup = (modelType: string) => {\r\n resetChildrenFilters(filters, srpFilters.Model)\r\n selectChildrenFilter(filters, srpFilters.Model, ...getSeriesBasedOnModelGroup(modelGroupFilters, modelType))\r\n\r\n handleRedirect(filters)\r\n }\r\n\r\n const handleRedirectYearAndModelGroup = (modelYear: string, modelType: string) => {\r\n resetChildrenFilters(filters, srpFilters.Model, srpFilters.Year)\r\n selectChildrenFilter(filters, srpFilters.Model, ...getSeriesBasedOnModelGroup(modelGroupFilters, modelType))\r\n selectChildrenFilter(filters, srpFilters.Year, modelYear)\r\n\r\n handleRedirect(filters)\r\n }\r\n\r\n return (\r\n \r\n {\r\n setExpand(!componentOpen)\r\n userInteraction(`Available Inventory: ${componentOpen ? 'Collapse' : 'Expand'}`)\r\n }}\r\n isExpand={componentOpen}\r\n leftActions={\r\n !ContentLoading &&\r\n !HeadingLoading &&\r\n ContentData?.length !== 0 && (\r\n <>\r\n handleFilterViewAllVehicles()}\r\n active={isViewAllClicked}\r\n style={{ marginRight: '2rem' }}\r\n >\r\n View All\r\n \r\n \r\n {displayFilters.BodyStyle.map((bodyStyle, idx) => {\r\n return (\r\n \r\n {bodyStyle}\r\n \r\n )\r\n })}\r\n \r\n \r\n {displayFilters.FuelType.map((type, index) => (\r\n \r\n {type}\r\n \r\n ))}\r\n \r\n \r\n {displayFilters.Make.map((type, index) => (\r\n cf.Value === type)?.Selected}\r\n >\r\n {type}\r\n \r\n ))}\r\n \r\n >\r\n )\r\n }\r\n rightActions={\r\n !(HeadingLoading || ContentLoading) && (\r\n \r\n \r\n View All Vehicles \r\n ({TotalRecords ?? 0})\r\n \r\n \r\n )\r\n }\r\n />\r\n \r\n \r\n {(ContentLoading || HeadingLoading) && }\r\n {!ContentLoading && !HeadingLoading && isEmpty(modelGroupFilters) && (\r\n \r\n \r\n \r\n {GENERIC_NO_VEHICLE_AVAILABLE_MESSAGE}
\r\n \r\n
\r\n )}\r\n\r\n {!ContentLoading && !HeadingLoading && !isEmpty(modelGroupFilters) && (\r\n \r\n {modelGroupFilters\r\n ?.filter(([mg, _]) => mg !== 'undefined')\r\n .map(([modelGroup, arrOfSeries]) => (\r\n ({ year, total: count }))}\r\n total={arrOfSeries?.length}\r\n onRedirect={handleRedirectModelGroup.bind(null, modelGroup)}\r\n handleRedirectYearAndModel={handleRedirectYearAndModelGroup}\r\n />\r\n ))}\r\n \r\n )}\r\n \r\n \r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledActivityTitle = styled.div`\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n font-size: 1.8rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n\r\n .total {\r\n display: inline;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n .icon {\r\n color: ${({ theme }) => theme.carousel.buttonHoverBackground};\r\n margin-bottom: 0.4rem;\r\n margin-right: 0.5rem;\r\n }\r\n .icon:hover {\r\n cursor: pointer;\r\n }\r\n\r\n a:hover {\r\n color: #810d2c;\r\n }\r\n`\r\n","import { Col } from 'react-bootstrap'\r\nimport {\r\n StyledVehicleAuctionInfo,\r\n StyledAuctionCardRow,\r\n StyledAuctionImage,\r\n StyledAuctionTitle,\r\n StyledAuctionText\r\n} from './VehicleAuction.styled'\r\nimport { IVehicleData, IVehicleInfo } from 'types/vehicleTypes'\r\nimport { IAuctionInfo } from 'types/auctionTypes'\r\nimport { PropsWithChildren, useEffect } from 'react'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\nimport { StyledVehicleBidBuyInformation } from './VehicleAuction.styled'\r\nimport { VehiclePriceSection } from 'modules/DealerVehicleManagement/VehiclePriceSection'\r\nimport { VehicleTags } from 'modules/DealerVehicleManagement/VehicleTags'\r\nimport { VehicleBidHistoryLink } from 'modules/DealerVehicleManagement/VehicleBidHistoryLink'\r\nimport { VehicleTimer } from 'modules/DealerVehicleManagement/VehicleTimer'\r\nimport { getVdpUrl } from 'utils/urlUtils'\r\nimport { Link } from 'components/Share/Link'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { useCountdown } from 'hooks/useCountdown'\r\n\r\ninterface IProps {\r\n vehicleData: IVehicleData\r\n vehicleShowOn?: string\r\n}\r\n\r\ninterface IVehicleLinkProps {\r\n vehicle: IVehicleInfo\r\n auctionInfo?: IAuctionInfo\r\n customName: string\r\n vehicleShowOn?: string\r\n}\r\n\r\nexport const VehicleLink = ({\r\n customName,\r\n vehicle,\r\n auctionInfo,\r\n children,\r\n vehicleShowOn\r\n}: PropsWithChildren) => {\r\n const handleClick = () => {\r\n setCustomClick(`Dashboard: BuyerActivity:${vehicleShowOn}:IndividualVehicle`, { usePageName: false })\r\n }\r\n\r\n const detailUrl = getVdpUrl(vehicle.InstanceID)\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}\r\n\r\nexport const VehicleAuction = ({ vehicleData, vehicleShowOn }: IProps) => {\r\n const { getBaseVehicle } = useVehicleStore()\r\n\r\n const { vehicle: vehicleInfo, auctionInfo } = vehicleData\r\n const { seconds: timeOut } = useCountdown(auctionInfo?.EndDate)\r\n\r\n const color = vehicleInfo.Properties?.find((item) => item.Code === 'Exterior Color')\r\n const mileage = vehicleInfo.Properties?.find((item) => item.Code === 'Odometer' && item.ID === 1)\r\n\r\n useEffect(() => {\r\n if (timeOut === 0 && vehicleData.auctionInfo?.IsHighestBidder) {\r\n getBaseVehicle(vehicleData)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [timeOut, vehicleData.auctionInfo?.IsHighestBidder])\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n {vehicleInfo.Title}\r\n \r\n \r\n {color?.Description}\r\n {mileage?.Description} miles\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport default VehicleAuction\r\n","import { StyledActivityTitle } from 'modules/BuyerActivity.styled'\r\nimport { getBidVehicles } from 'apis/dashboardApis'\r\nimport { GetBidVehiclesRequest, IGetBidVehiclesResponse } from 'types/vehicleTypes'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport Collapse from 'components/Collapse'\r\nimport { useVehicles } from 'hooks/useVehicles'\r\nimport CaretDownFill from 'images/icon/CaretDownFill'\r\nimport CaretRightFill from 'images/icon/CaretRightFill'\r\nimport { DEFAULT_SMALL_PAGE_SIZE } from 'common/constants'\r\nimport NoActivity from 'modules/BuyerActivity/NoActivity'\r\nimport { VehicleAuction } from 'modules/BuyerActivity/VehicleAuction'\r\nimport { Loader } from 'components/Loader'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useEffect } from 'react'\r\nimport { DtmComponentName, setCustomClick } from 'utils/analyticsUtils'\r\nimport { VehicleContextProvider } from 'modules/DealerVehicleManagement/VehicleContext'\r\nimport { getCurrentBidsUrl } from 'utils/urlUtils'\r\nimport { Link } from 'components/Share/Link'\r\n\r\ninterface IProps {\r\n isExpand?: boolean\r\n setExpand?: any\r\n}\r\nexport const CurrentBids = ({ isExpand, setExpand }: IProps) => {\r\n const { data: { Items: itemBids, TotalRecords: totalBids } = {} as IGetBidVehiclesResponse, loading: loadingBid } =\r\n useFetch(() => getBidVehicles(new GetBidVehiclesRequest(DEFAULT_SMALL_PAGE_SIZE)))\r\n const { endComponentLoad } = useDtmAnalytics()\r\n const { vehicles: vehicleBids } = useVehicles(itemBids)\r\n\r\n useEffect(() => {\r\n if (!loadingBid) {\r\n endComponentLoad(DtmComponentName.DashboardCurrentBids, itemBids)\r\n }\r\n }, [loadingBid, endComponentLoad, itemBids])\r\n\r\n const manageBidsUrl = getCurrentBidsUrl()\r\n\r\n if (loadingBid) {\r\n return \r\n }\r\n\r\n return (\r\n <>\r\n \r\n {isExpand ? : }\r\n YOUR CURRENT BIDS \r\n {\r\n setCustomClick('Dashboard: BuyerActivity: CurrentBids', { usePageName: false })\r\n event.stopPropagation()\r\n }}\r\n >\r\n ({totalBids ?? 0})\r\n \r\n \r\n \r\n \r\n {vehicleBids?.length > 0 ? (\r\n vehicleBids.map((item) => (\r\n \r\n \r\n \r\n ))\r\n ) : (\r\n \r\n )}\r\n
\r\n \r\n >\r\n )\r\n}\r\n","import { getWatchListVehicles } from 'apis/dashboardApis'\r\nimport { DEFAULT_SMALL_PAGE_SIZE } from 'common/constants'\r\nimport NoActivity from 'modules/BuyerActivity/NoActivity'\r\nimport VehicleAuction from 'modules/BuyerActivity/VehicleAuction'\r\nimport { VehicleContextProvider } from 'modules/DealerVehicleManagement/VehicleContext'\r\nimport { Loader } from 'components/Loader'\r\nimport { Link } from 'components/Share/Link'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { useVehicles } from 'hooks/useVehicles'\r\nimport CaretDownFill from 'images/icon/CaretDownFill'\r\nimport CaretRightFill from 'images/icon/CaretRightFill'\r\nimport { useEffect } from 'react'\r\nimport { Collapse } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { GetBidVehiclesRequest, IGetBidVehiclesResponse } from 'types/vehicleTypes'\r\nimport { DtmComponentName, setCustomClick } from 'utils/analyticsUtils'\r\nimport { getWatchlistUrl } from 'utils/urlUtils'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledActivityTitle } from './BuyerActivity.styled'\r\n\r\ninterface IProps {\r\n isExpand?: boolean\r\n setExpand?: any\r\n}\r\n\r\nexport const WatchList = ({ isExpand, setExpand }: IProps) => {\r\n const { data: { Items: items, TotalRecords: totalRecords } = {} as IGetBidVehiclesResponse, loading } = useFetch(() =>\r\n getWatchListVehicles(new GetBidVehiclesRequest(DEFAULT_SMALL_PAGE_SIZE))\r\n )\r\n const { vehicles } = useVehicles(items)\r\n const getLocalText = useGlobalStore((state) => state.getLocalText, shallow)\r\n const { endComponentLoad } = useDtmAnalytics()\r\n\r\n useEffect(() => {\r\n if (!loading) {\r\n endComponentLoad(DtmComponentName.DashboardWatchList, items)\r\n }\r\n }, [loading, endComponentLoad, items])\r\n\r\n const watchlistUrl = getWatchlistUrl()\r\n\r\n if (loading) {\r\n return \r\n }\r\n\r\n return (\r\n <>\r\n \r\n {isExpand ? : }\r\n WATCH LIST \r\n {\r\n setCustomClick('Dashboard: BuyerActivity: WatchList', { usePageName: false })\r\n event.stopPropagation()\r\n }}\r\n >\r\n ({totalRecords ?? 0})\r\n \r\n \r\n \r\n \r\n {vehicles?.length > 0 ? (\r\n vehicles.map((item) => (\r\n \r\n \r\n \r\n ))\r\n ) : (\r\n \r\n )}\r\n
\r\n \r\n >\r\n )\r\n}\r\n","import { HomeSectionHeader } from 'components/Header/HomeSectionHeader'\r\nimport { StyledBuyerActivitySection, StyledHomeSection } from 'components/Header/HomeSectionHeader.styled'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useExpand } from 'hooks/useExpand'\r\nimport { Col, Row } from 'react-bootstrap'\r\nimport { CurrentBids } from './CurrentBids'\r\nimport { WatchList } from './WatchList'\r\n\r\nconst initExpand = {\r\n componentOpen: true\r\n}\r\n\r\nexport const BuyerActivity = () => {\r\n const { state: expandState, action: expandAction } = useExpand({\r\n componentOpen: initExpand.componentOpen,\r\n groupOpen: new Array(2).fill(initExpand.componentOpen)\r\n })\r\n const { componentOpen, groupOpen } = expandState\r\n const { setExpand } = expandAction\r\n const { userInteraction } = useDtmAnalytics()\r\n\r\n return (\r\n \r\n {\r\n setExpand(!componentOpen)\r\n userInteraction(`Dashboard:InventoryView: BuyerActivity: ${componentOpen ? 'Collapse' : 'Expand'}`)\r\n }}\r\n isExpand={componentOpen}\r\n />\r\n \r\n \r\n \r\n \r\n setExpand(!groupOpen[0], 0)} />\r\n \r\n \r\n setExpand(!groupOpen[1], 1)} />\r\n \r\n \r\n
\r\n \r\n \r\n )\r\n}\r\n","import { SessionStorageKey, VIN_CHARACTERS_REGEX } from 'common/constants'\r\nimport { Formik } from 'formik'\r\nimport { Button, Col, Form, Row } from 'react-bootstrap'\r\nimport * as Yup from 'yup'\r\n\r\nconst SubmitGrounding = (values) => {\r\n sessionStorage.setItem(SessionStorageKey.GROUND_VIN, values.vin)\r\n window.location.href = '/grounding'\r\n}\r\n\r\nconst schema = Yup.object({\r\n vin: Yup.string().length(17, 'Must be 17 characters')\r\n})\r\n\r\nexport const GroundingImmediately = () => {\r\n return (\r\n \r\n \r\n \r\n {(props) => (\r\n \r\n )}\r\n \r\n \r\n
\r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyleGroundingOverview = styled.div`\r\n .custom-select:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n .form-control:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n .section-name {\r\n min-width: 12rem;\r\n }\r\n min-height: 10rem;\r\n`\r\n","import { smallScreen } from 'common/theme'\r\nimport { StyledVehicleAuctionInfo } from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyleVehicleDataCard = styled(StyledVehicleAuctionInfo).attrs({\r\n className: 'card h-100'\r\n})`\r\n margin-bottom: 0rem;\r\n margin-top: 0rem;\r\n .dashboard-reserver-bid {\r\n button {\r\n @media (min-width: ${smallScreen}) {\r\n width: 10rem;\r\n height: 3.5rem;\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyledPrice = styled.div`\r\n font-size: 1.6rem;\r\n font-weight: bold;\r\n`\r\nexport const StyledPurchaseButton = styled(Button)`\r\n min-width: 12rem;\r\n margin: 0.5rem 0.5rem;\r\n font-size: 1.1rem;\r\n`\r\nexport const StyledNotInterestedButton = styled(Button).attrs({\r\n className: 'btn-secondary'\r\n})`\r\n min-width: 12rem;\r\n margin: 0.5rem 0.5rem;\r\n font-size: 1.1rem;\r\n`\r\n","import { Col } from 'react-bootstrap'\r\nimport { IVehicleData, IVehicleInfo } from 'types/vehicleTypes'\r\nimport { IAuctionInfo } from 'types/auctionTypes'\r\nimport { PropsWithChildren, useEffect, useState } from 'react'\r\nimport { setCustomClick } from 'utils/analyticsUtils'\r\nimport { getBuyItNowUrl, getVdpUrl } from 'utils/urlUtils'\r\nimport { Link } from 'components/Share/Link'\r\nimport { useVehicleStore } from 'store/useVehicleStore'\r\nimport { useCountdown } from 'hooks/useCountdown'\r\nimport {\r\n StyledAuctionCardRow,\r\n StyledAuctionTitle,\r\n StyledAuctionText,\r\n StyledVehicleBidBuyInformation\r\n} from 'modules/BuyerActivity/VehicleAuction.styled'\r\nimport { StyledAuctionTimeRemaining } from 'modules/BuyerActivity/CountDown.styled'\r\nimport {\r\n StyledNotInterestedButton,\r\n StyledPrice,\r\n StyledPurchaseButton,\r\n StyleVehicleDataCard\r\n} from './VehicleDataCard.styled'\r\nimport { waiveVehicle } from 'apis/vehicleApis'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\n\r\ninterface IProps {\r\n showButton?: boolean\r\n vehicleData: IVehicleData\r\n isAwaitingInspection?: boolean\r\n}\r\n\r\ninterface IVehicleLinkProps {\r\n vehicle: IVehicleInfo\r\n auctionInfo?: IAuctionInfo\r\n customName: string\r\n vehicleShowOn?: string\r\n}\r\n\r\nexport const VehicleLink = ({\r\n customName,\r\n vehicle,\r\n auctionInfo,\r\n children,\r\n vehicleShowOn\r\n}: PropsWithChildren) => {\r\n const handleClick = () => {\r\n setCustomClick(`Dashboard: BuyerActivity:${vehicleShowOn}:IndividualVehicle`, { usePageName: false })\r\n }\r\n\r\n const detailUrl = getVdpUrl(vehicle.InstanceID)\r\n\r\n return (\r\n \r\n {children}\r\n \r\n )\r\n}\r\nconst purchaseHandle = (vehicleInstanceID: number) => {\r\n window.location.href = getBuyItNowUrl(vehicleInstanceID)\r\n}\r\n\r\nexport const VehicleDataCard = ({ vehicleData, isAwaitingInspection }: IProps) => {\r\n const { getBaseVehicle } = useVehicleStore()\r\n\r\n const { vehicle: vehicleInfo, auctionInfo } = vehicleData\r\n const { seconds: timeOut } = useCountdown(auctionInfo?.EndDate)\r\n\r\n const [isWaiveLoading, setIsWaiveLoading] = useState(false)\r\n\r\n useEffect(() => {\r\n if (timeOut === 0 && vehicleData.auctionInfo?.IsHighestBidder) {\r\n getBaseVehicle(vehicleData)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [timeOut, vehicleData.auctionInfo?.IsHighestBidder])\r\n\r\n const notInterestingHandle = async (vehicleInstanceID: number) => {\r\n setIsWaiveLoading(true)\r\n try {\r\n await waiveVehicle(vehicleInstanceID)\r\n } finally {\r\n setIsWaiveLoading(false)\r\n window.location.href = '/'\r\n }\r\n }\r\n return (\r\n <>\r\n {isWaiveLoading && }\r\n \r\n \r\n \r\n \r\n \r\n {vehicleInfo?.Title}\r\n \r\n \r\n VIN {vehicleInfo.VIN}\r\n {vehicleInfo?.MileageString} miles\r\n \r\n Inspection Status: {vehicleInfo?.inspectionStatusUpdates?.Status}\r\n \r\n \r\n Inspection ETA: {vehicleInfo?.inspectionStatusUpdates?.AssignedDateString}\r\n \r\n {!(vehicleInfo.OfferID !== undefined && vehicleInfo.OfferID > 0) && (\r\n \r\n Grounded On: \r\n {vehicleInfo?.GroundingCompletionDate}\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n {!(\r\n vehicleInfo.OfferID !== undefined &&\r\n vehicleInfo.OfferID > 0 &&\r\n vehicleInfo.CounterOfferPriceString !== undefined\r\n ) && {vehicleInfo?.FinalPriceString}}\r\n \r\n {vehicleInfo?.TimeLeft &&\r\n (isAwaitingInspection ? (\r\n \r\n {vehicleInfo?.TimeLeft}
\r\n in current status\r\n \r\n ) : (\r\n {vehicleInfo?.TimeLeft} left\r\n ))}\r\n \r\n
\r\n {vehicleInfo.showPrice && (\r\n \r\n notInterestingHandle(vehicleInfo.InstanceID)}>\r\n NOT INTERESTED\r\n \r\n purchaseHandle(vehicleInfo.InstanceID)}>\r\n PURCHASE\r\n \r\n
\r\n )}\r\n \r\n \r\n \r\n \r\n >\r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledGroudingLabelSection = styled.span`\r\n font-size: 1.6rem;\r\n text-align: center;\r\n width: 100%;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n\r\n & a {\r\n display: contents;\r\n font-size: 1.8rem;\r\n font-weight: 600;\r\n margin-left: 0.5rem;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n &:focus,\r\n &.focus {\r\n box-shadow: none;\r\n text-decoration: none;\r\n }\r\n }\r\n .icon {\r\n color: ${({ theme }) => theme.carousel.buttonHoverBackground};\r\n margin-bottom: 0.4rem;\r\n margin-right: 0.5rem;\r\n }\r\n .icon:hover {\r\n cursor: pointer;\r\n }\r\n`\r\nexport const StyledCountingTextAndIcon = styled.span<{ assetFolder?: string }>`\r\n color: ${({ theme }) => theme.carousel.buttonHoverBackground};\r\n /* svg > path {\r\n fill: ${({ theme }) => theme.carousel.buttonHoverBackground};\r\n } */\r\n svg:hover {\r\n cursor: pointer;\r\n }\r\n font-weight: 600;\r\n font-size: 1.8rem;\r\n`\r\n","import { useTheme } from 'styled-components'\r\n\r\nexport const ViewReportIcon = (props) => {\r\n const theme = useTheme()\r\n return (\r\n \r\n )\r\n}\r\nexport default ViewReportIcon\r\n","import CaretDownFill from 'images/icon/CaretDownFill'\r\nimport CaretRightFill from 'images/icon/CaretRightFill'\r\nimport { Button, Col, Collapse, OverlayTrigger, Row, Tooltip } from 'react-bootstrap'\r\nimport { VehicleDataCard } from './VehicleDataCard'\r\nimport { GROUNDING_OVERVIEW_SECTION } from 'common/constants'\r\nimport { StyledCountingTextAndIcon, StyledGroudingLabelSection } from './GroundingSection.styled'\r\nimport { IGroundingOverviewData } from 'types/vehicleTypes'\r\nimport { getAwaitingReportUrl, getFilterSeachResultUrl } from 'utils/urlUtils'\r\nimport ViewReportIcon from 'images/icon/ViewReportIcon'\r\ninterface IProps {\r\n data: IGroundingOverviewData\r\n isExpand?: boolean\r\n setExpand?: any\r\n}\r\n\r\nexport const GroundingSection = ({ data, isExpand, setExpand }: IProps) => {\r\n const HandleLink = (data) => {\r\n let viewReportURL\r\n if (data.sectionName === GROUNDING_OVERVIEW_SECTION.AWAITING_INSPECTION) {\r\n viewReportURL = getAwaitingReportUrl(\r\n data.minDateAwaitingInspection,\r\n data.maxDateAwaitingInspection,\r\n data.listOfVin\r\n )\r\n } else {\r\n viewReportURL = getFilterSeachResultUrl(data.filterField, data.filterValue)\r\n }\r\n window.location.href = viewReportURL\r\n }\r\n return (\r\n <>\r\n \r\n
\r\n \r\n \r\n {isExpand ? : }\r\n {data.sectionName.toUpperCase()} \r\n {data.sectionName !== GROUNDING_OVERVIEW_SECTION.AWAITING_INSPECTION && (\r\n \r\n )}\r\n \r\n {data.sectionName === GROUNDING_OVERVIEW_SECTION.AWAITING_INSPECTION && (\r\n \r\n ({data?.vehicleDataList?.length ?? 0}) \r\n \r\n View Report\r\n \r\n }\r\n >\r\n {\r\n HandleLink(data)\r\n event.stopPropagation()\r\n }}\r\n />\r\n \r\n \r\n )}\r\n \r\n
\r\n
\r\n \r\n {data.vehicleDataList?.map((item) => (\r\n \r\n \r\n \r\n ))}\r\n
\r\n \r\n
\r\n >\r\n )\r\n}\r\n","import { HomeSectionHeader } from 'components/Header/HomeSectionHeader'\r\nimport { StyledHomeSection, StyledHomeSectionBody } from 'components/Header/HomeSectionHeader.styled'\r\nimport { Loader } from 'components/Loader'\r\nimport { useExpand } from 'hooks/useExpand'\r\nimport { useEffect, useState } from 'react'\r\nimport { Collapse } from 'react-bootstrap'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport { IGroundingOverviewData } from 'types/vehicleTypes'\r\nimport { getOrderNumber } from 'utils/utils'\r\nimport shallow from 'zustand/shallow'\r\nimport { GroundingImmediately } from './GroundingImmediately'\r\nimport { StyleGroundingOverview } from './GroundingOverview.styled'\r\nimport { GroundingSection } from './GroundingSection'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { Rules } from 'common/rules'\r\n\r\nexport const GroundingOverview = ({ loading, widgetData, widgetLoading }) => {\r\n const [groundingData, setGroundingData] = useState([])\r\n const { state: expandState, action: expandAction } = useExpand({ componentOpen: true } as never)\r\n const { groundingData: data } = useDashboardStore((state) => state, shallow)\r\n const [isVisible, setIsVisible] = useState(true)\r\n const { componentOpen, groupOpen } = expandState\r\n const { setExpand, initGroup } = expandAction\r\n const isInRule = useGlobalStore((state) => state.isInRule, shallow)\r\n useEffect(() => {\r\n if (groundingData) {\r\n initGroup({ totalGroup: groundingData.length, initValue: true })\r\n }\r\n }, [groundingData])\r\n\r\n useEffect(() => {\r\n if (!widgetLoading) {\r\n let orderNumber = getOrderNumber('WidgetDiv3_Grounding', widgetData)\r\n if (orderNumber == 0) return setIsVisible(false)\r\n if (data) {\r\n let groundingSectionData = [] as IGroundingOverviewData[]\r\n data?.groupHeader?.forEach((item) => {\r\n groundingSectionData.push({\r\n listOfVin: data?.ListOfVin,\r\n sectionName: item.headerText,\r\n filterField: item.filterField,\r\n filterValue: item.filterValue,\r\n vehicleDataList: item.subGroup,\r\n minDateAwaitingInspection: data?.MinDateAwaitingInspection,\r\n maxDateAwaitingInspection: data?.MaxDateAwaitingInspection\r\n } as IGroundingOverviewData)\r\n })\r\n setGroundingData(groundingSectionData)\r\n }\r\n }\r\n }, [data, widgetLoading])\r\n\r\n return (\r\n <>\r\n {isVisible && (\r\n \r\n {\r\n setExpand(!componentOpen)\r\n }}\r\n isExpand={componentOpen}\r\n />\r\n \r\n \r\n \r\n {[Rules.VIEW_GROUNDING_QUICK_START].every((rule) => isInRule(rule)) && }\r\n {loading ? (\r\n \r\n ) : (\r\n <>\r\n {groundingData?.map((item, index) => (\r\n setExpand(!groupOpen[index], index)}\r\n />\r\n ))}\r\n >\r\n )}\r\n \r\n \r\n \r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import styled from 'styled-components'\r\nimport { gridBreakPoints } from 'common/theme'\r\n\r\nexport const StyledYTDSectionBody = styled.div`\r\n padding: 2rem 20rem;\r\n min-height: 15rem;\r\n position: relative;\r\n @media screen and (max-width: ${gridBreakPoints.xxl}) {\r\n padding: 2rem 15rem;\r\n }\r\n @media screen and (max-width: ${gridBreakPoints.lg}) {\r\n padding: 2rem 5rem;\r\n .table-body td {\r\n min-width: 5rem;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledMyActivitySection = styled(StyledYTDSectionBody)`\r\n .table-head {\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n color: #cccccc;\r\n width: 100%;\r\n th {\r\n border-top: none;\r\n position: relative;\r\n font-weight: 400;\r\n border-right: 1px solid #ccc;\r\n &:first-child,\r\n :last-child {\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n position: sticky;\r\n z-index: 2;\r\n }\r\n &:first-child {\r\n min-width: 18rem;\r\n left: 0;\r\n }\r\n &:last-child {\r\n right: 0;\r\n border-left: 1px solid #ccc;\r\n }\r\n }\r\n }\r\n table tbody > tr {\r\n &.table-row:nth-child(odd) > td {\r\n background: ${({ theme }) => theme.colors.tableStriped};\r\n }\r\n &.table-row:nth-child(even) > td {\r\n background: ${({ theme }) => theme.colors.inputBackgroundColor};\r\n }\r\n & > td:first-child,\r\n td:last-child {\r\n position: sticky;\r\n z-index: 1;\r\n }\r\n & > td:first-child {\r\n left: 0;\r\n }\r\n & > td:last-child {\r\n right: 0;\r\n }\r\n }\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n .table {\r\n font-size: 1.2rem;\r\n }\r\n }\r\n`\r\n","import { DataTable, DEFAULT_TABLE_HEIGHT } from 'components/DataTable'\r\nimport { HomeSectionHeader } from 'components/Header/HomeSectionHeader'\r\nimport { StyledHomeSection } from 'components/Header/HomeSectionHeader.styled'\r\nimport Collapse from 'components/Collapse'\r\nimport { StyledMyActivitySection } from './MyActivityYTD.styled'\r\nimport { Loader } from 'components/Loader'\r\nimport { useEffect, useState } from 'react'\r\nimport { useExpand } from 'hooks/useExpand'\r\nimport { MY_ACTIVITY_YTD } from 'common/constants'\r\nimport { IDashboardVehicles } from 'types/vehicleTypes'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport shallow from 'zustand/shallow'\r\n\r\ninterface IMyActivity {\r\n loading: boolean\r\n}\r\n\r\nexport const MyActivityYTD = ({ loading }: IMyActivity) => {\r\n const [myActivityData, setMyActivityData] = useState([])\r\n const { groundingData } = useDashboardStore((state) => state, shallow)\r\n const { state: expandState, action: expandAction } = useExpand({ componentOpen: true } as never)\r\n\r\n const { componentOpen } = expandState\r\n const { setExpand } = expandAction\r\n\r\n useEffect(() => {\r\n if (groundingData) {\r\n let groundedList = { name: MY_ACTIVITY_YTD.GROUNDED }\r\n let purchasedGroup = { name: MY_ACTIVITY_YTD.GROUNDED_PURCHASED }\r\n let auctionGroup = { name: MY_ACTIVITY_YTD.WEB_AUCTION_PURCHASED }\r\n\r\n groundingData?.ytd?.forEach((item) => {\r\n groundedList = { ...groundedList, [item.month]: item.grounded }\r\n purchasedGroup = { ...purchasedGroup, [item.month]: item.purchased }\r\n auctionGroup = { ...auctionGroup, [item.month]: item.auctionPurchased }\r\n })\r\n setMyActivityData([groundedList, purchasedGroup, auctionGroup])\r\n }\r\n }, [groundingData])\r\n\r\n return (\r\n \r\n {\r\n setExpand(!componentOpen)\r\n }}\r\n isExpand={componentOpen}\r\n />\r\n \r\n \r\n {loading && }\r\n {!loading && (\r\n {\r\n return {cell?.row?.original.name}\r\n }\r\n },\r\n ...groundingData?.ytd.map((item) => {\r\n return {\r\n Header: item.month,\r\n Cell: ({ cell }) => {\r\n return {cell?.row?.original[item.month]}\r\n }\r\n }\r\n })\r\n ]}\r\n data={myActivityData}\r\n >\r\n )}\r\n \r\n \r\n \r\n )\r\n}\r\n","import { searchVehicles } from 'apis/vehicleApis'\r\nimport { SRP_INIT_QUERY, VIN_CHARACTERS_REGEX } from 'common/constants'\r\nimport { isAnyChildrenFilterExistValue, resetChildrenFilters, selectChildrenFilter } from 'common/helpers'\r\nimport { MultiLanguageCode } from 'common/languageCodes'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport { Formik } from 'formik'\r\nimport { useEffect, useState } from 'react'\r\nimport { Alert, Button, Col, Form, Row } from 'react-bootstrap'\r\nimport { FormattedMessage } from 'react-intl'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport { ISearchFilterResult } from 'types/vehicleTypes'\r\nimport { getVdpUrl } from 'utils/urlUtils'\r\nimport * as Yup from 'yup'\r\nimport shallow from 'zustand/shallow'\r\n\r\ninterface IProps {\r\n loading: boolean\r\n}\r\n\r\nexport const SearchVin = ({ loading: ContentLoading }: IProps) => {\r\n const [searching, setSearching] = useState(false)\r\n const [showMessage, setShowMesage] = useState(false)\r\n const { filters: ContentData } = useDashboardStore((state) => state, shallow)\r\n const [searchFilters, setSearchFilters] = useState([])\r\n\r\n useEffect(() => {\r\n if (!ContentLoading) {\r\n setSearchFilters([...ContentData] as ISearchFilterResult[])\r\n }\r\n }, [ContentLoading])\r\n\r\n const SubmitSearch = async (values) => {\r\n resetChildrenFilters(searchFilters)\r\n selectChildrenFilter(searchFilters, 'VIN', values.vin)\r\n try {\r\n setSearching(true)\r\n const response = await searchVehicles({\r\n ...SRP_INIT_QUERY,\r\n SearchQuery: { ...SRP_INIT_QUERY.SearchQuery, SearchFilters: searchFilters }\r\n })\r\n if (response) {\r\n if (!isAnyChildrenFilterExistValue(searchFilters, 'VIN', 'VIN', values.vin)) {\r\n setShowMesage(true)\r\n } else {\r\n window.location.href = getVdpUrl(response.Items?.[0]?.vehicle?.InstanceID)\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error)\r\n } finally {\r\n setSearching(false)\r\n }\r\n }\r\n\r\n const schema = Yup.object({\r\n vin: Yup.string().length(17, 'Must be 17 characters')\r\n })\r\n\r\n return (\r\n <>\r\n {\r\n setShowMesage(false)\r\n }}\r\n >\r\n {(props) => (\r\n \r\n )}\r\n \r\n {searching && }\r\n {showMessage && (\r\n setShowMesage(false)} dismissible>\r\n \r\n \r\n )}\r\n >\r\n )\r\n}\r\n","import { searchVehicles } from 'apis/vehicleApis'\r\nimport { AVAILABLE_INVENTORY_INIT_QUERY, SessionStorageKey } from 'common/constants'\r\nimport { resetChildrenFilters, selectChildrenFilter } from 'common/helpers'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport { Formik } from 'formik'\r\nimport { useEffect, useState } from 'react'\r\nimport { Button, Col, Form, Row } from 'react-bootstrap'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport { ISearchFilterResult } from 'types/vehicleTypes'\r\nimport { resetSRPFilter } from 'utils/menuUtils'\r\nimport { getSearchUrl } from 'utils/urlUtils'\r\nimport shallow from 'zustand/shallow'\r\n\r\ninterface IProps {\r\n loading: boolean\r\n}\r\nexport const SearchSaleChannel = ({ loading: ContentLoading }: IProps) => {\r\n const [searching, setSearching] = useState(false)\r\n\r\n const { filters: ContentData } = useDashboardStore((state) => state, shallow)\r\n const [saleChannel, setSaleChannel] = useState(null)\r\n const [searchFilters, setSearchFilters] = useState([])\r\n\r\n useEffect(() => {\r\n if (!ContentLoading) {\r\n const channels = ContentData.find(\r\n (e) => e.DBFieldName === 'saleChannel' || e.FieldName === 'Sales Channel'\r\n )?.ChildrenFilter.map((item) => item.Value)\r\n setSearchFilters([...ContentData] as ISearchFilterResult[])\r\n if (!!channels) {\r\n setSaleChannel(channels)\r\n }\r\n }\r\n }, [ContentLoading])\r\n\r\n const handleChangeSaleChannel = (saleChannel: string) => {\r\n resetChildrenFilters(searchFilters)\r\n selectChildrenFilter(searchFilters, 'Sales Channel', saleChannel)\r\n }\r\n\r\n const handleRedirect = (filter?: ISearchFilterResult[]) => {\r\n resetSRPFilter()\r\n sessionStorage.setItem(SessionStorageKey.SEARCH_FILTERS, filter ? JSON.stringify(filter) : null)\r\n window.location.href = getSearchUrl()\r\n }\r\n\r\n const SubmitSearch = async () => {\r\n try {\r\n setSearching(true)\r\n const response = await searchVehicles({\r\n ...AVAILABLE_INVENTORY_INIT_QUERY,\r\n SearchQuery: { ...AVAILABLE_INVENTORY_INIT_QUERY.SearchQuery, SearchFilters: searchFilters }\r\n })\r\n if (response) {\r\n handleRedirect(searchFilters)\r\n }\r\n } catch (error) {\r\n console.log(error)\r\n } finally {\r\n setSearching(false)\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n \r\n {(props) => (\r\n \r\n )}\r\n \r\n {searching && }\r\n >\r\n )\r\n}\r\n","import { Button } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyleSearchGeneral = styled.span<{ assetFolder?: string }>`\r\n .custom-select:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n .form-control:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n .save-search-btn {\r\n color: red !important;\r\n }\r\n .section-name {\r\n min-width: 12rem;\r\n }\r\n`\r\nexport const StyledHomeSectionLink = styled(Button).attrs(({ className, variant, href }) => ({\r\n className: `d-flex align-items-center ${className ?? ''}`.trim(),\r\n variant: variant ?? 'link',\r\n href: href ?? null\r\n}))`\r\n font-size: 1.6rem;\r\n font-weight: 350;\r\n &:hover,\r\n &:active {\r\n text-decoration: none;\r\n }\r\n\r\n &:focus,\r\n &.focus {\r\n box-shadow: none;\r\n text-decoration: none;\r\n }\r\n\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n font-weight: bold;\r\n position: relative;\r\n`\r\n","import { HomeSectionHeader } from 'components/Header/HomeSectionHeader'\r\nimport {\r\n StyledHomeSection,\r\n StyledHomeSectionBody,\r\n StyledHomeSectionHeaderActionSection\r\n} from 'components/Header/HomeSectionHeader.styled'\r\nimport { useExpand } from 'hooks/useExpand'\r\nimport { Row, Col, Collapse } from 'react-bootstrap'\r\nimport { getSaveSearchUrl } from 'utils/urlUtils'\r\nimport { SearchVin } from './SearchVin'\r\nimport { SearchSaleChannel } from './SearchSaleChannel'\r\nimport { Loader } from 'components/Loader'\r\nimport { StyledHomeSectionLink, StyleSearchGeneral } from './SearchGeneral.styled'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\ninterface IProps {\r\n isFilterLoading: boolean\r\n}\r\nconst NavigateToSaveSearch = () => {\r\n window.location.href = getSaveSearchUrl()\r\n}\r\n\r\nconst RightTitle = () => {\r\n return (\r\n \r\n My Saved Searches\r\n \r\n )\r\n}\r\nexport const SearchGeneral = ({ isFilterLoading }: IProps) => {\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n const { state: expandState, action: expandAction } = useExpand({ componentOpen: true } as never)\r\n const { componentOpen } = expandState\r\n const { setExpand } = expandAction\r\n return (\r\n \r\n {\r\n setExpand(!componentOpen)\r\n }}\r\n isExpand={componentOpen}\r\n leftActions={<>>}\r\n rightActions={RightTitle()}\r\n />\r\n \r\n \r\n \r\n \r\n {isFilterLoading ? (\r\n \r\n ) : (\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n )}\r\n
\r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { SessionStorageKey } from 'common/constants'\r\n\r\nexport const setListingBreadcrumb = (pageTitle: string, url: string) => {\r\n sessionStorage.removeItem(SessionStorageKey.DETAIL_BREADCRUMB)\r\n\r\n url = url.replace('?clearSearch=true', '')\r\n const filterIndex = url.indexOf('?filters')\r\n if (filterIndex > -1) {\r\n url = url.substring(0, filterIndex)\r\n }\r\n\r\n sessionStorage.setItem(\r\n SessionStorageKey.LIST_BREADCRUMB,\r\n JSON.stringify({\r\n description: pageTitle,\r\n url: url\r\n })\r\n )\r\n}\r\n","import { largeScreen } from 'common/theme'\r\nimport { StyledHomeSectionHeaderTitle } from 'components/Header/HomeSectionHeader.styled'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledDashboardPlaceholder = styled.div`\r\n @media (min-width: ${largeScreen}) {\r\n ${StyledHomeSectionHeaderTitle} {\r\n justify-content: left;\r\n padding-left: calc(12.5vw - 80px);\r\n }\r\n }\r\n`\r\nexport const StyledDashboardSlide = styled.div`\r\n margin: 0rem auto 3rem;\r\n`\r\n","import { getDashboardWidgetConfigurationDetails } from 'apis/dashboardApis'\r\nimport { Rules } from 'common/rules'\r\nimport { SlideShow } from 'components/SlideShow/SlideShow'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { Layout } from 'layouts/Layout'\r\nimport { AvailableInventory } from 'modules/AvailableInventory'\r\nimport { BuyerActivity } from 'modules/BuyerActivity'\r\nimport { DefaultErrorBoundary } from 'modules/DefaultErrorBoundary'\r\nimport { GroundingOverview } from 'modules/GroundingOverview/GroundingOverview'\r\nimport { MyActivityYTD } from 'modules/MyActivityYTD/MyActivityYTD'\r\nimport { SearchGeneral } from 'modules/SearchGeneral/SearchGeneral'\r\nimport { PropsWithChildren, useEffect, useLayoutEffect, useState } from 'react'\r\nimport { RouteProps, useLocation } from 'react-router-dom'\r\nimport { useDashboardStore } from 'store/useDashboardStore'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { setListingBreadcrumb } from 'utils/breadcrumbUtils'\r\nimport shallow from 'zustand/shallow'\r\nimport { BUYER_TYPE_ID, SessionStorageKey } from '../common/constants'\r\nimport { StyledDashboardPlaceholder, StyledDashboardSlide } from './Dashboard.styled'\r\n\r\ninterface IAuthenticatedRouteProps extends PropsWithChildren {\r\n allowedRules?: Rules[]\r\n}\r\n\r\nconst AuthorizedComponent = ({ allowedRules, children }: IAuthenticatedRouteProps) => {\r\n const isInRule = useGlobalStore((state) => state.isInRule, shallow)\r\n\r\n return {allowedRules?.some((rule) => isInRule(rule)) && children}
\r\n}\r\n\r\nexport const Dashboard = () => {\r\n const { endPageLoad } = useDtmAnalytics()\r\n const { fetchGroundingData, fetchFilters } = useDashboardStore((state) => state, shallow)\r\n const { loading: filterLoading } = useFetch(() => fetchFilters())\r\n const { loading: groundingDataLoading } = useFetch(() => fetchGroundingData())\r\n const [buyerID] = useGlobalStore((state) => [state.userClaims.CurrentBuyerID])\r\n\r\n const {\r\n userClaims: { DealershipName: dealerShipName, AssociatedBuyers: associatedBuyers }\r\n } = useGlobalStore(\r\n (state) => ({\r\n userClaims: state.userClaims\r\n }),\r\n shallow\r\n )\r\n const [showSearch, setShowSearch] = useState(true)\r\n\r\n const location = useLocation()\r\n const { loading: widgetLoading, data: widgetData } = useFetch(() => getDashboardWidgetConfigurationDetails())\r\n\r\n useLayoutEffect(() => {\r\n window.sessionStorage.removeItem(SessionStorageKey.SEARCH_FILTERS)\r\n window.sessionStorage.removeItem(SessionStorageKey.VEHICLE_INSTANCES)\r\n window.sessionStorage.removeItem(SessionStorageKey.GROUND_VIN)\r\n setListingBreadcrumb('Dashboard', location.pathname)\r\n }, [])\r\n\r\n useEffect(() => {\r\n const dealer = associatedBuyers?.find((item) => item.Description === dealerShipName)\r\n if (\r\n dealer.BuyerTypeID === BUYER_TYPE_ID.CORPORATE_OFFICE_UPSTREAM ||\r\n dealer.BuyerTypeID === BUYER_TYPE_ID.CORPORATE_OFFICE_NON_UPSTREAM\r\n ) {\r\n setShowSearch(false)\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!filterLoading) {\r\n endPageLoad()\r\n }\r\n }, [filterLoading, endPageLoad])\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {showSearch && (\r\n \r\n \r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { Layout } from 'layouts/Layout'\r\nimport { Alert } from 'react-bootstrap'\r\n\r\ninterface IProps {\r\n message: string\r\n}\r\n\r\nexport const ErrorPage = ({ message }: IProps) => {\r\n return (\r\n \r\n \r\n {message}
\r\n \r\n \r\n )\r\n}\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledStepperContainer = styled.div<{ step4ButtonClicked?: boolean }>`\r\n flex: 1;\r\n transform: translateY(1.3rem);\r\n\r\n .StepperContainer-0-2-1 {\r\n padding: 0;\r\n width: 100%;\r\n\r\n @media (min-width: ${gridBreakPoints.md}) {\r\n width: 76%;\r\n }\r\n @media (min-width: ${gridBreakPoints.lg}) {\r\n width: 70%;\r\n }\r\n }\r\n\r\n #RFS-Connector {\r\n border-top-width: 7px;\r\n transform: translateY(-3px);\r\n }\r\n\r\n /* #RFS-StepContainer:last-child #RFS-ConnectorContainer span {\r\n border-color: ${({ theme }) => theme.colors.inputBorder} !important;\r\n } */\r\n\r\n button > span {\r\n display: none;\r\n }\r\n\r\n #RFS-StepButton.active ~ #RFS-LabelContainer {\r\n #RFS-Label {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n }\r\n #RFS-StepButton.completed ~ #RFS-LabelContainer {\r\n #RFS-Label {\r\n color: ${({ theme }) => theme.colors.stepperCompleteColor};\r\n }\r\n }\r\n\r\n #RFS-LabelContainer > span {\r\n font-family: 'Nissan AG Bold', 'Verdana', 'sans-serif', -apple-system;\r\n font-weight: 700;\r\n font-size: 11px;\r\n }\r\n\r\n #RFS-StepButton.completed:disabled:hover {\r\n background-color: ${({ theme }) => theme.colors.stepperCompleteColor};\r\n }\r\n`\r\n","import create from 'zustand'\r\nimport { GroundingRenderStep } from './RenderStep'\r\n\r\ninterface IGroundingAction {\r\n activeStep: number\r\n groundingStepInfor: GroundingStep[]\r\n isBack: boolean\r\n isSubmit: boolean\r\n\r\n setActiveStep: (code: number) => void\r\n setGroundingStepInfor: (data: GroundingStep[]) => void\r\n setIsBack: (back: boolean) => void\r\n setIsSubmit: (back: boolean) => void\r\n}\r\n\r\nexport const useGroundingActionStore = create((set, get) => ({\r\n activeStep: GroundingRenderStep.GRD_ENTER_VIN,\r\n groundingStepInfor: [],\r\n isBack: false,\r\n isSubmit: false,\r\n\r\n setActiveStep: (stepIndex) => {\r\n const steps = [...get().groundingStepInfor]\r\n const step = steps.find((s) => s.stepIndex === stepIndex) as GroundingStep\r\n if (!step) {\r\n return\r\n }\r\n step.active = true\r\n step.completed = false\r\n set((state) => ({ ...state, activeStep: step.stepIndex, groundingStepInfor: steps }))\r\n },\r\n setGroundingStepInfor: (data) => {\r\n set((state) => ({ ...state, groundingStepInfor: data }))\r\n },\r\n setIsBack: (back) => {\r\n set((state) => ({ ...state, isBack: back }))\r\n },\r\n setIsSubmit: (submit) => {\r\n set((state) => ({ ...state, isSubmit: submit }))\r\n }\r\n}))\r\n\r\nexport interface GroundingStep {\r\n label: string\r\n stepIndex: number\r\n active: boolean\r\n disabled: boolean\r\n clicked: boolean\r\n completed: boolean\r\n isBack: boolean\r\n onClick: () => void\r\n}\r\n","import {\r\n ERROR_ODOMETER_INVALID_INPUT,\r\n ERROR_ODOMETER_REQUIRED_MESSAGE,\r\n ERROR_VIN_INVALID_INPUT_MESSAGE,\r\n ERROR_VIN_INVALID_LENGTH_MESSAGE,\r\n ERROR_VIN_REQUIRED_MESSAGE,\r\n GENERAL_ERROR_MESSAGE\r\n} from 'common/constants'\r\nimport { IVehicleInfo } from '../vehicleTypes'\r\nimport * as yup from 'yup'\r\nimport { ISystemSetting } from 'types/baseTypes'\r\nimport { validate } from 'utils/vehicleUtils'\r\n\r\n// const vinRegex = /^([A-Z\\d]{3})[A-Z]{2}\\d{2}([A-Z\\d]{1})([X\\d]{1})([A-Z\\d]{3})\\d{5}$/\r\nconst vinRegex = /[a-zA-Z0-9]/\r\nconst odometerRegex = /^[0-9]+$/\r\nconst phoneRegex = /^[0-9]{3}-[0-9]{3}-[0-9]{4}$/\r\nconst mailRegex =\r\n /^((?:(?:[a-zA-Z0-9_\\-\\\\.]+)@(?:(?:\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(?:(?:[a-zA-Z0-9\\\\-]+\\.)+))(?:[a-zA-Z]{2,4}|[0-9]{1,3})(?:\\]?)(?:\\s*;\\s*|\\s*$))*)$/\r\nexport const mailListRegex =\r\n // eslint-disable-next-line no-useless-escape\r\n /^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5}){1,25}([ ]{0,1};[ ]{0,1}([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5}){1,25})*$/\r\n\r\nexport interface IGroundedVehicleInfo extends IVehicleInfo {\r\n GroundingCompletionDate: string\r\n TimeLeft: string\r\n}\r\n\r\nexport const enum DispositionOption {\r\n 'EMPLOYEE_RETURN' = 12,\r\n 'LESSEE_RETURN' = 13,\r\n 'DEALER_INVENTORY_PURCHASE' = 14,\r\n 'EMPLOYEE_PURCHASE' = 15,\r\n 'LESSEE_PURCHASE' = 16,\r\n 'DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT' = 17\r\n}\r\n\r\nexport interface IVinSearchForm {\r\n VIN: string\r\n}\r\n\r\nexport const initialVinValues: IVinSearchForm = {\r\n VIN: ''\r\n}\r\n\r\nexport const initialValues: IVinSearchForm = {\r\n VIN: ''\r\n}\r\nexport interface ILocationDropDown {\r\n ID: number\r\n Description: string\r\n Address1: string\r\n Address2: string\r\n City: string\r\n State: string\r\n StateCode: string\r\n Zip: string\r\n AddressTypeID: number\r\n}\r\n\r\nexport interface IGroundingForm {\r\n vehicleReturnDate: Date\r\n currentVIN: string\r\n odometerReading: string\r\n confirmOdometerReading: string\r\n newVIN?: string\r\n newBrand?: string\r\n additionalComment?: string\r\n requiresNewVIN: boolean\r\n requiresNewVINNotBrand: boolean\r\n requiresNewVINForCampaign: boolean\r\n vinValidationList: ISystemSetting\r\n campaign?: number\r\n}\r\n\r\nexport interface IAddressForm {\r\n address: string\r\n address2: string\r\n city: string\r\n zip: string\r\n stateCode: string\r\n}\r\n\r\nexport const initialAddressValue: IAddressForm = {\r\n address: '',\r\n address2: '',\r\n city: '',\r\n zip: '',\r\n stateCode: '-1'\r\n}\r\n\r\n// export const initialGroundingValue: IGroundingForm = {\r\n// vehicleReturnDate: null,\r\n// currentVIN: '',\r\n// odometerReading: '',\r\n// confirmOdometerReading: '',\r\n// newVIN: '',\r\n// newBrand: '',\r\n// requiresNewVIN: '',\r\n// requiresNewVINNotBrand: 'true',\r\n// vinValidationList: {} as ISystemSetting,\r\n// campaign: -1\r\n// }\r\n\r\nexport const addressValidateSchema = yup.object({\r\n address: yup.string().trim().required(GENERAL_ERROR_MESSAGE),\r\n city: yup.string().trim().required(GENERAL_ERROR_MESSAGE),\r\n zip: yup.string().trim().required(GENERAL_ERROR_MESSAGE),\r\n stateCode: yup.string().notOneOf(['-1'], GENERAL_ERROR_MESSAGE)\r\n})\r\n\r\nexport const vinValidateSchema = yup.object({\r\n vinNumber: yup\r\n .string()\r\n .trim()\r\n .required(ERROR_VIN_REQUIRED_MESSAGE)\r\n .min(17, ERROR_VIN_INVALID_LENGTH_MESSAGE)\r\n .max(17, ERROR_VIN_INVALID_LENGTH_MESSAGE)\r\n .matches(vinRegex, ERROR_VIN_INVALID_INPUT_MESSAGE)\r\n})\r\n\r\nexport const groundingValueValidateSchema = (values: IGroundingForm) => {\r\n return yup.object({\r\n vehicleReturnDate: yup.string().required(GENERAL_ERROR_MESSAGE),\r\n requiresNewVIN: yup.string().trim(),\r\n currentVIN: yup.string().matches(vinRegex, ERROR_VIN_INVALID_INPUT_MESSAGE),\r\n odometerReading: yup\r\n .string()\r\n .trim()\r\n .required(GENERAL_ERROR_MESSAGE)\r\n .matches(odometerRegex, ERROR_ODOMETER_INVALID_INPUT),\r\n confirmOdometerReading: yup\r\n .string()\r\n .trim()\r\n .required(GENERAL_ERROR_MESSAGE)\r\n .matches(odometerRegex, ERROR_ODOMETER_INVALID_INPUT)\r\n .oneOf([yup.ref('odometerReading'), null], 'The odometer readings do not match.'),\r\n newVIN: yup\r\n .string()\r\n .trim()\r\n .when(['requiresNewVIN', 'requiresNewVINNotBrand', 'requiresNewVINForCampaign'], {\r\n is: (requiresNewVIN, requiresNewVINNotBrand, requiresNewVINForCampaign) =>\r\n (requiresNewVIN === 'true' && requiresNewVINNotBrand === true) || requiresNewVINForCampaign === true,\r\n then: (yup) =>\r\n yup\r\n .required(ERROR_VIN_REQUIRED_MESSAGE)\r\n .min(17, ERROR_VIN_INVALID_INPUT_MESSAGE)\r\n .max(17, ERROR_VIN_INVALID_INPUT_MESSAGE)\r\n .test(\r\n 'is-same-grounding-vin',\r\n 'You have entered the VIN being grounded. Please enter the New VIN.',\r\n (newVIN) => {\r\n return newVIN.toUpperCase() !== values.currentVIN.toUpperCase()\r\n }\r\n )\r\n .test((newVIN, context) => {\r\n const firstThreeChars = newVIN.substring(0, 3)\r\n const isInvalidNisInfVin =\r\n values.vinValidationList.Value === '1' &&\r\n values.vinValidationList.ValueString.split(',').indexOf(firstThreeChars) === -1\r\n if (isInvalidNisInfVin) {\r\n return context.createError({\r\n message:\r\n 'VIN must be a Nissan or INFINITI vehicle, please re-enter valid VIN. You may also contact Customer Care directly at 1-866-RPM-0333 or 1-866-776-0333'\r\n })\r\n }\r\n if (!validate(newVIN))\r\n return context.createError({\r\n message:\r\n 'You have entered an invalid VIN. Please re-enter. You may also contact Customer Care directly at 1-866-RPM-0333 or 1-866-776-0333'\r\n })\r\n else return true\r\n }),\r\n otherwise: (yup) => yup.notRequired()\r\n }),\r\n newBrand: yup.string().trim()\r\n })\r\n}\r\n","import { Stepper } from 'react-form-stepper'\r\nimport { useEffect, useState } from 'react'\r\nimport { StyledStepperContainer } from './GroundingStepper.styled'\r\nimport { useGroundingActionStore } from './store/useGroundingActionStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { GroundingRenderStep } from './store/RenderStep'\r\nimport { useTheme } from 'styled-components'\r\n\r\ninterface IGroundingStepperProps {\r\n onClick: (code: number) => void\r\n}\r\n\r\nconst CustomStepper = (props) => {\r\n const theme = useTheme()\r\n return (\r\n \r\n {\r\n const current = e.target as HTMLButtonElement\r\n if (current.tagName != 'BUTTON') return\r\n props?.onStepClicked?.(+current.getAttribute('stepIndex'))\r\n }}\r\n connectorStateColors={true}\r\n connectorStyleConfig={{\r\n completedColor: theme.colors.stepperCompleteColor,\r\n activeColor: theme.colors.stepperCompleteColor,\r\n disabledColor: theme.colors.inputBorder\r\n }}\r\n styleConfig={{\r\n size: '20px',\r\n activeBgColor: theme.colors.InfinitiOnlyColor,\r\n completedBgColor: theme.colors.stepperCompleteColor,\r\n inactiveBgColor: theme.colors.inputBorder,\r\n activeTextColor: theme.colors.InfinitiOnlyColor,\r\n completedTextColor: theme.colors.stepperCompleteColor,\r\n inactiveTextColor: theme.colors.inputBorder\r\n }}\r\n />\r\n \r\n )\r\n}\r\n\r\nexport const GroundingStepper = (props: IGroundingStepperProps) => {\r\n const { activeStep, groundingStepInfor, isBack, isSubmit, setIsSubmit, setIsBack } = useGroundingActionStore(\r\n (state) => state,\r\n shallow\r\n )\r\n\r\n return (\r\n {\r\n if (stepIndex === activeStep) return\r\n if (\r\n activeStep === GroundingRenderStep.GRD_RESULT &&\r\n (stepIndex === GroundingRenderStep.GRD_OPTIONS ||\r\n stepIndex === GroundingRenderStep.GRD_TURN_IN ||\r\n stepIndex === GroundingRenderStep.GRD_ENTER_VIN)\r\n ) {\r\n return\r\n }\r\n props.onClick(stepIndex)\r\n }}\r\n />\r\n )\r\n}\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledDividerWidthText = styled.div`\r\n display: flex;\r\n align-items: center;\r\n border-bottom: 0.1rem solid ${({ theme }) => theme.colors.borderInput};\r\n h2 {\r\n white-space: nowrap;\r\n\r\n @media (max-width: ${gridBreakPoints.md}) {\r\n white-space: wrap;\r\n }\r\n font-weight: 600;\r\n font-size: 16px;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n\r\n .divider {\r\n width: 100%;\r\n height: 1px;\r\n background-color: #999;\r\n margin: 20px;\r\n margin-right: 5px;\r\n opacity: 0.2;\r\n }\r\n`\r\n","import React from 'react'\r\nimport { StyledDividerWidthText } from './DividerWidthText.styled'\r\n\r\ninterface IProps {\r\n title: string\r\n}\r\n\r\nconst DividerWidthText = ({ title }: IProps) => {\r\n return (\r\n \r\n {title}
\r\n \r\n \r\n )\r\n}\r\n\r\nexport default DividerWidthText\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledGroundInformation = styled.div`\r\n padding: 5px 3rem;\r\n\r\n border-radius: 3px;\r\n box-shadow: 0px -1px 2px rgb(0 0 0 / 15%), 2px 2px 2px rgb(0 0 0 / 25%);\r\n margin: 5px 0 30px 0;\r\n display: block;\r\n background-color: white;\r\n font-size: 14px;\r\n\r\n label:first-of-type {\r\n font-weight: bold;\r\n font-size: 16px;\r\n margin-bottom: 0;\r\n text-transform: uppercase;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n cursor: pointer;\r\n }\r\n\r\n span {\r\n line-height: 30px;\r\n }\r\n\r\n svg {\r\n fill: ${({ theme }) => theme.colors.primary};\r\n vertical-align: text-bottom;\r\n margin-right: 5px;\r\n }\r\n\r\n > .row {\r\n padding-bottom: 12px;\r\n\r\n .left-field,\r\n .right-field {\r\n padding: 0;\r\n }\r\n }\r\n\r\n .warning-label {\r\n font-weight: normal;\r\n color: red;\r\n }\r\n .vehicle-cost {\r\n /* font-size: 1.4em; */\r\n text-align: center;\r\n max-width: fit-content;\r\n padding: 5px 15px;\r\n }\r\n\r\n .condition-tag {\r\n padding: 6px 15px;\r\n margin-left: 15px;\r\n }\r\n\r\n @media (max-width: 500px) {\r\n .price-tag {\r\n margin-top: 10px;\r\n }\r\n }\r\n\r\n .alert-info {\r\n color: black;\r\n font-weight: bold;\r\n }\r\n`\r\n\r\nexport const StyledVehicleDetailText = styled.div`\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n\r\n span {\r\n font-weight: 600;\r\n }\r\n\r\n a {\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.InfinitiLinkColor};\r\n cursor: pointer;\r\n }\r\n`\r\n\r\nexport const StyledVehicleDetailDivider = styled.div`\r\n align-items: center;\r\n cursor: pointer;\r\n padding: 8px 0;\r\n\r\n label {\r\n white-space: nowrap;\r\n }\r\n`\r\n","import create from 'zustand'\r\nimport { GroundingReturn } from '../../../types/Grounding/GroundingResult'\r\n\r\ninterface IGroundingData {\r\n groundingData: GroundingReturn\r\n defaultGroundingData: GroundingReturn\r\n groundingCompletionData: GroundingReturn\r\n showTerms?: boolean\r\n alreadyConfirmRecall?: boolean\r\n alreadyConfirmGeneralModal?: boolean\r\n\r\n setGroundingData: (data: GroundingReturn) => void\r\n setDefaultGroundingData: (data: GroundingReturn) => void\r\n setGroundingCompletionData: (data: GroundingReturn) => void\r\n setShowTerms: (data: boolean) => void\r\n setAlreadyConfirmRecall: (data: boolean) => void\r\n setAlreadyConfirmGeneralModal: (data: boolean) => void\r\n}\r\n\r\nexport const useGroundingStore = create((set, get) => ({\r\n groundingData: {} as GroundingReturn,\r\n defaultGroundingData: {} as GroundingReturn,\r\n groundingCompletionData: {} as GroundingReturn,\r\n showTerms: false,\r\n alreadyConfirmRecall: false,\r\n alreadyConfirmGeneralModal: false,\r\n\r\n setGroundingData: (data) => {\r\n set((state) => ({ ...state, groundingData: data }))\r\n },\r\n setDefaultGroundingData: (data) => {\r\n set((state) => ({ ...state, defaultGroundingData: data }))\r\n },\r\n setGroundingCompletionData: (data) => {\r\n set((state) => ({ ...state, groundingCompletionData: data }))\r\n },\r\n setShowTerms: (data) => {\r\n set((state) => ({ ...state, showTerms: data }))\r\n },\r\n setAlreadyConfirmRecall: (data) => {\r\n set((state) => ({ ...state, alreadyConfirmRecall: data }))\r\n },\r\n setAlreadyConfirmGeneralModal: (data) => {\r\n set((state) => ({ ...state, alreadyConfirmGeneralModal: data }))\r\n }\r\n}))\r\n","import { Link } from 'react-router-dom'\r\nimport {\r\n StyledGroundInformation,\r\n StyledVehicleDetailDivider,\r\n StyledVehicleDetailText\r\n} from './GroundingVehicleDetails.styled'\r\nimport { Col, Row } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { useGroundingStore } from 'modules/Grounding/store/useGroundingStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { formatShortContext } from 'utils/stringUtils'\r\n\r\nconst GroundingVehicleDetails = () => {\r\n const [groundingData] = useGroundingStore((state) => [state.groundingData], shallow)\r\n const [getSystemSettings, getLocalText] = useGlobalStore((state) => [state.getSystemSetting, state.getLocalText])\r\n const hideLesseeName = Number(getSystemSettings('HIDE_LESSEE_NAME_FROM_GROUNDING_SCREEN')) ?? 0\r\n const hideLesseeAddress = Number(getSystemSettings('HIDE_LESSEE_ADDRESS_FROM_GROUNDING_SCREEN')) ?? 0\r\n const receivingDealershipPhoneVisibility =\r\n Number(getSystemSettings('DISPLAY_RECEIVING_DEALERSHIP_PHONE_SECTION')) ?? 0\r\n const gradeLabel = getLocalText('GradeLabel', 'Grade')\r\n\r\n const computedPurchasePriceString = (purchasePrice: string) => {\r\n if (purchasePrice && purchasePrice !== '') {\r\n groundingData.residualPrice = groundingData?.purchasePrice\r\n groundingData.residualPriceString = purchasePrice\r\n if (groundingData?.purchasePriceString && groundingData?.selectedDisposition) {\r\n const selectedCompaign = groundingData?.Campaigns.find(\r\n (campaign) => campaign.ID === groundingData?.SelectedCampaignId\r\n )\r\n if (groundingData?.SelectedCampaignId === 0) return purchasePrice\r\n else if (selectedCompaign !== undefined && groundingData?.SelectedCampaign.IsPullAhead)\r\n return groundingData?.residualPriceString\r\n else return purchasePrice\r\n }\r\n return purchasePrice\r\n }\r\n }\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n {groundingData?.conditionAlert !== undefined && groundingData?.conditionAlert !== '' && (\r\n \r\n CONDITION REPORT PRESENT \r\n
\r\n )}\r\n\r\n {groundingData?.purchasePriceString !== undefined &&\r\n groundingData?.purchasePriceString !== null &&\r\n groundingData?.purchasePriceString !== '$0' &&\r\n groundingData?.purchasePriceString !== '' && (\r\n \r\n \r\n {computedPurchasePriceString(groundingData?.purchasePriceString)}\r\n
\r\n \r\n )}\r\n
\r\n\r\n \r\n \r\n \r\n Vehicle Description: \r\n \r\n {groundingData?.vehicleDescription}\r\n \r\n \r\n \r\n VIN: {groundingData?.VIN}\r\n \r\n \r\n \r\n \r\n Lease Type: {groundingData?.fleetName}\r\n \r\n \r\n Account Number: {groundingData?.accountNumber}\r\n \r\n \r\n \r\n \r\n Maturity Date: {groundingData?.maturityDate}\r\n \r\n {hideLesseeName !== 1 && (\r\n \r\n Lessee Name: {groundingData?.lesseeName}\r\n \r\n )}\r\n \r\n \r\n {receivingDealershipPhoneVisibility === 1 && (\r\n \r\n {gradeLabel}: {groundingData?.Grade ? groundingData?.Grade : 'N/A'}\r\n \r\n )}\r\n {hideLesseeAddress !== 1 && (\r\n \r\n Lessee Address: \r\n {formatShortContext(\r\n 30,\r\n groundingData?.lesseeAddress +\r\n groundingData?.lesseeAddress2 +\r\n ', ' +\r\n groundingData?.lesseeCity +\r\n ', ' +\r\n groundingData?.lesseeState +\r\n ' ' +\r\n groundingData?.lesseeZip\r\n ) + '...'}\r\n \r\n )}\r\n \r\n
\r\n \r\n )\r\n}\r\n\r\nexport default GroundingVehicleDetails\r\n","// import { colorInput, inputFontSize, defaultColor, mediumScreen, smallScreen, largeScreen } from 'common/theme'\r\nimport { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledGroundingOptions = styled.div`\r\n --padding-content: 3rem;\r\n --padding-content-mobile: 2rem;\r\n\r\n .dropdown:focus,\r\n .dropdown:focus-visible,\r\n .dropdown:hover {\r\n box-shadow: none;\r\n }\r\n\r\n .dropdown-menu {\r\n box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.24);\r\n }\r\n\r\n .dropdown-item.active,\r\n .dropdown-item:focus-visible,\r\n .dropdown-item:hover {\r\n outline: 0;\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n color: #fff;\r\n }\r\n\r\n input:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n .option-confirm {\r\n p:first-child {\r\n font-size: 15px;\r\n font-weight: 600;\r\n }\r\n\r\n .pull-ahead {\r\n display: block;\r\n .has-error {\r\n font-weight: bold;\r\n font-size: 13px;\r\n color: #a94442;\r\n }\r\n .program-info-desc {\r\n margin-left: 25px;\r\n font-size: 13px;\r\n }\r\n .program-info {\r\n margin-left: 25px;\r\n font-size: 13px;\r\n margin-top: 10px;\r\n }\r\n }\r\n\r\n .option {\r\n margin-top: 10px;\r\n }\r\n\r\n div {\r\n display: flex;\r\n align-items: start;\r\n\r\n input {\r\n min-width: 16px;\r\n min-height: 25px;\r\n margin-right: 10px;\r\n cursor: pointer;\r\n }\r\n\r\n label {\r\n vertical-align: bottom;\r\n margin-bottom: 0.3rem;\r\n /* font-weight: normal; */\r\n cursor: pointer;\r\n transform: translateY(3px);\r\n }\r\n }\r\n }\r\n\r\n .indication-row {\r\n margin-top: 10px;\r\n }\r\n\r\n .indication-row {\r\n margin-top: 10px;\r\n margin-bottom: 5px;\r\n\r\n .indication-radio {\r\n display: flex;\r\n align-items: center;\r\n\r\n .radio-button {\r\n transform: translateY(0px);\r\n }\r\n }\r\n }\r\n\r\n .radio-button {\r\n display: flex;\r\n align-items: center;\r\n cursor: pointer;\r\n transition: all 0.2s ease-in-out;\r\n transform: translateY(5px);\r\n }\r\n\r\n .radio-button input[type='radio'] {\r\n display: none;\r\n }\r\n\r\n .radio-checkmark {\r\n display: inline-block;\r\n position: relative;\r\n width: 16px;\r\n height: 16px;\r\n margin-right: 10px;\r\n border: 1px solid #333;\r\n border-radius: 50%;\r\n }\r\n\r\n .radio-checkmark:before {\r\n content: '';\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%) scale(0);\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n background-color: #333;\r\n transition: all 0.2s ease-in-out;\r\n }\r\n\r\n .radio-button input[type='radio']:checked ~ .radio-checkmark:before {\r\n transform: translate(-50%, -50%) scale(1);\r\n }\r\n\r\n form {\r\n padding: 20px var(--padding-content);\r\n border-radius: 3px;\r\n box-shadow: 0px -1px 2px rgb(0 0 0 / 15%), 2px 2px 2px rgb(0 0 0 / 25%);\r\n margin: 5px 0 30px 0;\r\n display: block;\r\n background-color: white;\r\n\r\n > p:first-child {\r\n text-align: end;\r\n font-weight: 600;\r\n font-size: 16px;\r\n margin-bottom: -12px;\r\n }\r\n }\r\n\r\n .error-label {\r\n min-height: 1.8rem;\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-size: 1.2rem !important;\r\n margin-bottom: 0;\r\n margin-top: 8px;\r\n font-weight: bold;\r\n }\r\n\r\n .required-field:after {\r\n content: '*';\r\n color: ${({ theme }) => theme.colors.primary};\r\n margin-left: 0.2rem;\r\n }\r\n\r\n button {\r\n margin-left: 0;\r\n }\r\n\r\n .col-lg-4,\r\n .col-lg-5,\r\n .col-lg-6,\r\n .col-lg-7,\r\n .col-lg-1,\r\n .col-md-6,\r\n .col-md-5,\r\n .col-md-1,\r\n .col-sm-4,\r\n .col-lg-12 {\r\n padding: 0;\r\n }\r\n\r\n .row {\r\n margin-right: 0;\r\n margin-left: 0;\r\n }\r\n\r\n .text-divider {\r\n padding: 0;\r\n margin-top: 15px;\r\n text-transform: uppercase;\r\n\r\n h2 {\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-weight: bold;\r\n }\r\n\r\n :first-child {\r\n margin-top: 0;\r\n }\r\n }\r\n\r\n .right-field,\r\n .left-field {\r\n label {\r\n font-weight: 600;\r\n }\r\n\r\n .col-lg-6 {\r\n padding: 0;\r\n }\r\n }\r\n\r\n .alert {\r\n max-width: 100% !important;\r\n }\r\n\r\n .left-field {\r\n padding-right: calc(var(--padding-content) / 2);\r\n }\r\n\r\n .right-field {\r\n padding-left: calc(var(--padding-content) / 2);\r\n margin-top: 1rem;\r\n }\r\n\r\n .dropdown-container {\r\n height: 30px;\r\n }\r\n\r\n .actual-mileage-warning {\r\n min-height: 1.8rem;\r\n line-height: 1.8rem;\r\n font-size: 15px;\r\n color: red;\r\n margin-bottom: 0;\r\n }\r\n\r\n .odometer-input {\r\n margin-top: 16px;\r\n margin-bottom: 10px;\r\n }\r\n\r\n .odometer-warning {\r\n margin-bottom: 10px;\r\n p:before {\r\n content: '! ';\r\n }\r\n\r\n .odometer-warning-label {\r\n font-size: 15px;\r\n color: red;\r\n text-align: end;\r\n margin: 0;\r\n }\r\n\r\n .form-check {\r\n text-align: end;\r\n\r\n input {\r\n width: 16px;\r\n height: 16px;\r\n cursor: pointer;\r\n }\r\n\r\n label {\r\n cursor: pointer;\r\n font-weight: normal;\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyledGroundingOption = styled.div`\r\n .campaign-title {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n margin-bottom: 20px;\r\n }\r\n\r\n .disposition-title {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n margin-bottom: 20px;\r\n margin-top: 32px;\r\n }\r\n\r\n .grounding-data-option {\r\n display: flex;\r\n position: relative;\r\n align-items: start;\r\n margin-bottom: 1rem;\r\n margin-top: 1rem;\r\n width: 100%;\r\n /* \r\n input[type='radio']:after {\r\n width: 15px;\r\n height: 15px;\r\n border-radius: 15px;\r\n top: -2px;\r\n left: -1px;\r\n position: relative;\r\n background-color: #d1d3d1;\r\n content: '';\r\n display: inline-block;\r\n visibility: visible;\r\n border: 2px solid white;\r\n } */\r\n\r\n .purchase-content {\r\n transform: translateY(3px);\r\n\r\n .purchase-price {\r\n margin-bottom: 4px;\r\n font-weight: bold;\r\n line-height: 1.5;\r\n font-size: 14px;\r\n }\r\n }\r\n\r\n input {\r\n min-width: 16px;\r\n min-height: 25px;\r\n margin-right: 10px;\r\n cursor: pointer;\r\n }\r\n\r\n label {\r\n white-space: nowrap;\r\n vertical-align: bottom;\r\n margin-bottom: 0.3rem;\r\n font-weight: normal;\r\n cursor: pointer;\r\n }\r\n\r\n &:not(:last-child) {\r\n padding-right: 5%;\r\n }\r\n }\r\n\r\n .date-picker {\r\n display: flex;\r\n align-items: center;\r\n margin-top: 2rem;\r\n margin-bottom: 1rem;\r\n }\r\n\r\n .date-label {\r\n transform: translateY(-1rem);\r\n }\r\n\r\n .date-input {\r\n /* transform: translateY(1rem); */\r\n margin-left: 3rem;\r\n }\r\n a {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkColor};\r\n :hover {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n`\r\n\r\nexport const StyledGroundingOdometer = styled.div`\r\n .col-lg-6:last-child {\r\n padding-right: 0;\r\n padding-right: 0;\r\n }\r\n\r\n .odometer-input {\r\n input {\r\n max-width: 380px;\r\n }\r\n }\r\n`\r\n\r\nexport const StyledGroundingItem = styled.div`\r\n button {\r\n margin-top: 0;\r\n }\r\n\r\n .grounding-item {\r\n span {\r\n margin-bottom: 0.5rem;\r\n font-weight: bold;\r\n display: flex;\r\n }\r\n }\r\n\r\n .grounding-item-container {\r\n width: 100%;\r\n }\r\n\r\n .grounding-item-container > .text-divider {\r\n padding-right: calc(var(--padding-content) / 2);\r\n }\r\n\r\n .grounding-contact-container > .text-divider {\r\n padding-left: calc(var(--padding-content) / 2);\r\n }\r\n`\r\n\r\nexport const StyledGroundingAdditional = styled.div`\r\n display: inline-block;\r\n width: 100%;\r\n\r\n textarea {\r\n font-size: 14px;\r\n resize: none;\r\n }\r\n\r\n .dropdown span {\r\n max-width: 90%;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n\r\n .grounding-notice {\r\n margin-top: 30px;\r\n margin-left: -20px;\r\n }\r\n\r\n .addition-groups-button {\r\n display: flex;\r\n flex-wrap: nowrap;\r\n\r\n > div {\r\n /* width: 50%; */\r\n text-align: end;\r\n }\r\n\r\n .btn.btn-link {\r\n padding: 0.3rem;\r\n }\r\n svg:hover {\r\n opacity: 0.5;\r\n }\r\n }\r\n\r\n .col-lg-1 {\r\n text-align: end;\r\n }\r\n #termsLink {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkColor};\r\n :hover {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n .btn-link {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n`\r\n\r\nexport const StyledGroundingReview = styled.div`\r\n display: block;\r\n text-align: end;\r\n margin-top: 20px;\r\n margin-bottom: 15px;\r\n .btn-link {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n :hover {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n`\r\n\r\nexport const StyledVehicleDetailDivider = styled.div`\r\n align-items: center;\r\n cursor: pointer;\r\n padding: 8px 0;\r\n\r\n label {\r\n white-space: nowrap;\r\n }\r\n`\r\n\r\nexport const StyledDatePickerWithIcon = styled.div`\r\n display: flex;\r\n align-items: center;\r\n border: 1px solid #ced4da;\r\n border-radius: 0.4rem;\r\n background: #ffffff;\r\n max-width: 160px;\r\n .dateInput {\r\n width: 100%;\r\n height: 100%;\r\n }\r\n .dateInput input {\r\n cursor: default;\r\n border: none;\r\n width: calc(100% + 2.5rem);\r\n background: transparent;\r\n }\r\n .react-datepicker__day {\r\n &--selected,\r\n &--in-range,\r\n &--keyboard-selected {\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n }\r\n svg {\r\n width: 2.5rem;\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n`\r\n\r\nexport const StyledLabelRequired = styled.span`\r\n font-weight: bolder;\r\n display: flex;\r\n ::after {\r\n content: '*';\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n`\r\n","import { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledConfirmModal = styled(Modal)`\r\n * {\r\n font-size: 15px;\r\n }\r\n\r\n padding-right: 0 !important;\r\n\r\n .modal-dialog {\r\n max-width: 600px;\r\n }\r\n\r\n strong {\r\n font-weight: 600;\r\n }\r\n\r\n .modal-body {\r\n padding: 1rem 1.4rem 1.4rem;\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n }\r\n\r\n .modal-header {\r\n margin: 0.5rem 1rem;\r\n padding: 0.5rem 1rem 0 !important;\r\n border-bottom: none;\r\n\r\n button {\r\n padding: 0;\r\n span {\r\n font-size: 25px;\r\n }\r\n }\r\n }\r\n\r\n .modal-warning-message {\r\n color: red;\r\n }\r\n\r\n .modal-btn-group {\r\n text-align: end;\r\n margin-top: 10px;\r\n\r\n button {\r\n min-width: 30px;\r\n font-size: 15px;\r\n }\r\n\r\n button:not(:first-child) {\r\n margin-left: 20px;\r\n }\r\n }\r\n`\r\n","import { Modal, Button } from 'react-bootstrap'\r\nimport { StyledConfirmModal } from './GroundingConfirmModal.styled'\r\nimport { divide } from 'lodash'\r\n\r\ninterface IProps {\r\n header?: string\r\n content: string\r\n show: boolean\r\n events?: {\r\n onClose?: any\r\n setShowModal?: any\r\n handleAcknowledgedConfirm?: any\r\n handleClickXButton?: any\r\n }\r\n isShowHeader?: boolean\r\n isShowButton?: boolean\r\n isEmbedHtml?: boolean\r\n isShowYesButton?: boolean\r\n isShowNoButton?: boolean\r\n isBackdropStatic?: boolean\r\n}\r\n\r\nexport const GroundingConfirmModal = ({\r\n content,\r\n show,\r\n events,\r\n header,\r\n isShowHeader,\r\n isShowButton,\r\n isEmbedHtml,\r\n isShowYesButton,\r\n isShowNoButton,\r\n isBackdropStatic\r\n}: IProps) => {\r\n return (\r\n events.handleClickXButton()}\r\n backdrop={isBackdropStatic ? 'static' : true}\r\n centered\r\n >\r\n {isShowHeader && (\r\n \r\n {header}\r\n \r\n )}\r\n \r\n {isEmbedHtml ? : {content}
}\r\n {isShowButton && (\r\n \r\n \r\n \r\n
\r\n )}\r\n \r\n \r\n )\r\n}\r\nexport default GroundingConfirmModal\r\n","import styled from 'styled-components'\r\nconst StyledDateTimePicker = styled.div`\r\n .react-datepicker {\r\n font-size: 1.3rem;\r\n }\r\n\r\n .react-datepicker__current-month {\r\n font-size: 1.5rem;\r\n }\r\n\r\n .react-datepicker__header {\r\n padding-top: 6px;\r\n }\r\n\r\n .react-datepicker__navigation {\r\n top: 13px;\r\n }\r\n\r\n .react-datepicker__day-name,\r\n .react-datepicker__day {\r\n margin: 0.5rem;\r\n }\r\n`\r\n\r\nexport default StyledDateTimePicker\r\n","import DatePicker from 'react-datepicker'\r\nimport StyledDateTimePicker from './DateTimePicker.styled'\r\nimport 'react-datepicker/dist/react-datepicker.css'\r\nimport { ComponentProps } from 'react'\r\n\r\nexport const DateTimePicker = ({ ...props }: ComponentProps) => {\r\n return (\r\n \r\n \r\n \r\n )\r\n}\r\nexport default DateTimePicker\r\n","import styled from 'styled-components'\r\n\r\nexport const inputFontSize = '14px'\r\n\r\nexport const StyledAddressModal = styled.div`\r\n div label {\r\n font-weight: 600;\r\n }\r\n\r\n input {\r\n min-height: 30px;\r\n font-size: ${inputFontSize};\r\n :focus {\r\n background-color: #fff;\r\n border-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n outline: 0;\r\n }\r\n /* box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25); */\r\n }\r\n\r\n .required-field:after {\r\n content: '*';\r\n color: ${({ theme }) => theme.colors.primary};\r\n margin-left: 0.2rem;\r\n }\r\n\r\n .save-option {\r\n input {\r\n min-width: 16px;\r\n min-height: 16px;\r\n margin-right: 10px;\r\n cursor: pointer;\r\n }\r\n\r\n label {\r\n vertical-align: bottom;\r\n margin-bottom: 0.3rem;\r\n font-weight: normal;\r\n text-transform: uppercase;\r\n cursor: pointer;\r\n }\r\n\r\n .col-sm-12 {\r\n margin-top: 5px;\r\n font-size: 15px;\r\n display: flex;\r\n }\r\n }\r\n\r\n .dropdown:focus,\r\n .dropdown:focus-visible,\r\n .dropdown:hover {\r\n box-shadow: none;\r\n border: none;\r\n }\r\n\r\n .dropdown-menu {\r\n height: 250px;\r\n overflow-y: scroll;\r\n }\r\n .dropdown-title,\r\n .dropdown-item {\r\n font-weight: normal;\r\n color: #495057;\r\n }\r\n .dropdown-item.active,\r\n .dropdown-item:focus-visible,\r\n .dropdown-item:hover {\r\n outline: 0;\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n color: #fff;\r\n }\r\n\r\n .form-text {\r\n font-size: 1.2rem;\r\n font-weight: bold;\r\n }\r\n`\r\n","import { smallScreen } from 'common/theme'\r\nimport { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const contentFontSize = '15px'\r\nexport const commonButtonWidth = '140px'\r\n\r\nexport const StyledModal = styled(Modal)`\r\n * {\r\n font-size: ${contentFontSize};\r\n max-width: ${(props) => props.customWidth || '1000px'};\r\n }\r\n\r\n z-index: 1040;\r\n\r\n .modal-header {\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n .modal-title {\r\n font-size: 20px;\r\n font-weight: 600;\r\n color: white;\r\n margin-left: 5px;\r\n }\r\n }\r\n\r\n .modal-header .close {\r\n min-width: 0;\r\n margin-right: 5px;\r\n opacity: 0.8;\r\n font-size: 25px;\r\n }\r\n\r\n .modal-header .close span {\r\n font-size: 20px;\r\n color: white;\r\n }\r\n\r\n .modal-body {\r\n padding: 20px;\r\n }\r\n\r\n .btn-group {\r\n display: flex;\r\n gap: 15px;\r\n justify-content: flex-end;\r\n margin-top: 1rem;\r\n\r\n button {\r\n width: ${commonButtonWidth};\r\n max-width: ${commonButtonWidth};\r\n }\r\n\r\n span {\r\n text-align: right;\r\n }\r\n }\r\n\r\n @media (max-width: ${smallScreen}) {\r\n padding: 0 !important;\r\n }\r\n`\r\n","import { useEffect, useState } from 'react'\r\nimport { Modal, Row, Col } from 'react-bootstrap'\r\nimport { StyledAddressModal } from './AddressModal.styled'\r\nimport { Button, FormControl as Input } from 'react-bootstrap'\r\nimport { Form, Formik } from 'formik'\r\nimport { IAddressForm, initialAddressValue, addressValidateSchema } from 'types/Grounding/groundingTypes'\r\nimport { StyledModal } from 'components/Modal.styled'\r\nimport { AddressTypes, GENERAL_ERROR_MESSAGE, SaveLocationOption } from 'common/constants'\r\nimport { DropdownList } from 'layouts/DropdownList'\r\nimport { DropDownData, LocationDropDown } from 'types/Grounding/GroundingResult'\r\nimport { ValidationErrorMessage } from 'components/Forms'\r\ninterface IAddressProps {\r\n defaultAddressDetail: LocationDropDown\r\n stateList: DropDownData[]\r\n show: boolean\r\n isEditAddress: boolean\r\n events: {\r\n onClose: any\r\n handleSaveAddress: any\r\n setIsSaveAddressToBuyer: any\r\n }\r\n}\r\n\r\nexport const AddressModal = ({ defaultAddressDetail, isEditAddress, stateList, show, events }: IAddressProps) => {\r\n const [isSubmit, setIsSubmit] = useState(false)\r\n const [addressDetail] = useState(defaultAddressDetail)\r\n const [saveOptionSelected, setSaveOptionSelected] = useState(0)\r\n const [initLocationData, setInitLocationData] = useState(initialAddressValue)\r\n\r\n useEffect(() => {\r\n if (defaultAddressDetail != null) {\r\n setInitLocationData({\r\n address: defaultAddressDetail.Address1,\r\n address2: defaultAddressDetail.Address2,\r\n city: defaultAddressDetail.City,\r\n zip: defaultAddressDetail.Zip,\r\n stateCode: defaultAddressDetail?.StateCode\r\n })\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n const handleSaveAddress = (values: IAddressForm) => {\r\n if (saveOptionSelected === 0 && !isEditAddress) {\r\n return\r\n }\r\n\r\n events.handleSaveAddress({\r\n AddressLineOne: values.address,\r\n AddressLineTwo: values.address2,\r\n Town: values.city,\r\n StateId: stateList?.find((x) => x.FieldDescription === values.stateCode)?.ID ?? 0,\r\n PostCode: values.zip,\r\n AddressId:\r\n isEditAddress && defaultAddressDetail?.AddressTypeID != AddressTypes.HEAD_OFFICE ? defaultAddressDetail?.ID : 0,\r\n AddressTypeId:\r\n isEditAddress && defaultAddressDetail?.AddressTypeID != AddressTypes.HEAD_OFFICE\r\n ? defaultAddressDetail?.AddressTypeID\r\n : AddressTypes.VEHICLE_PICKUP_LOCATION\r\n })\r\n }\r\n\r\n const handleSaveOptionChange = (e: any) => {\r\n setSaveOptionSelected(Number(e.target.id))\r\n if (Number(e.target.id) === SaveLocationOption.SAVE_TO_BUYER) {\r\n events.setIsSaveAddressToBuyer(true)\r\n } else {\r\n events.setIsSaveAddressToBuyer(false)\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n Vehicle Location\r\n \r\n \r\n handleSaveAddress(values)}\r\n validateOnBlur={false}\r\n >\r\n {(props) => (\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n )\r\n}\r\n","import { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledConfirmModal = styled(Modal)`\r\n .modal-content {\r\n width: 120%;\r\n }\r\n .modal-body {\r\n padding: 2rem !important;\r\n }\r\n .recall-dialog-container {\r\n margin: auto;\r\n /* border: 1px solid #888; */\r\n width: 600px;\r\n height: auto;\r\n }\r\n .recall-dialog-title {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: white;\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n width: 100%;\r\n font-size: 21px !important;\r\n height: auto;\r\n max-height: 80px;\r\n position: relative !important;\r\n }\r\n .recall-dialog-title-icon {\r\n height: 35px;\r\n transform: translateX(6px) translateY(-2px) scale(0.8);\r\n }\r\n .recall-dialog-content {\r\n height: auto;\r\n width: 597px;\r\n overflow-y: auto;\r\n margin-bottom: 5px;\r\n max-height: 450px;\r\n font-size: 16px;\r\n }\r\n .recall-dialog-content div {\r\n margin: 0;\r\n padding: 15px 0 0 0;\r\n text-align: justify;\r\n }\r\n .recall-dialog-content-class div p {\r\n margin: 0;\r\n padding: 5px 0 0 0;\r\n }\r\n .recall-dialog-content::-webkit-scrollbar {\r\n width: 8px;\r\n }\r\n .recall-dialog-content::-webkit-scrollbar-thumb {\r\n background: grey;\r\n border-radius: 10px;\r\n }\r\n .recall-dialog-content::-webkit-scrollbar-track {\r\n background: #f1f1f1;\r\n }\r\n .recall-dialog-content::-webkit-scrollbar-thumb:hover {\r\n background: #555;\r\n }\r\n .recall-dialog-title-text {\r\n color: white;\r\n width: 95%;\r\n word-break: break-word;\r\n padding: 10px 0px 0px 10px;\r\n text-align: center;\r\n border: none;\r\n max-height: 400px;\r\n font-size: 17px;\r\n }\r\n .recall-dialog-acknowledge-button {\r\n margin-top: 10px;\r\n padding: 20px 28px;\r\n color: white;\r\n outline: none;\r\n background-color: black;\r\n border: none;\r\n text-transform: uppercase;\r\n border-radius: 3px;\r\n line-height: 1;\r\n display: block;\r\n font-size: 14px;\r\n }\r\n\r\n .recall-dialog-acknowledge-button:hover {\r\n background-color: #666;\r\n color: #fff;\r\n }\r\n .recall-dialog-close-button {\r\n padding: 0 !important;\r\n color: white !important;\r\n float: right;\r\n line-height: 1;\r\n display: block;\r\n transform: translateY(2px);\r\n }\r\n /*.recall-dialog-close-button:hover,\r\n.recall-dialog-close-button:focus {\r\n color: #b3b3b3;\r\n text-decoration: none;\r\n cursor: pointer;\r\n}*/\r\n .recall-dialog-title-icon {\r\n height: 35px;\r\n margin-right: 6px;\r\n }\r\n\r\n .m-0 {\r\n margin: 0px;\r\n }\r\n\r\n .p-0 {\r\n padding: 0px;\r\n }\r\n\r\n .p-1 {\r\n padding: 10px;\r\n }\r\n`\r\n","import { useGroundingStore } from 'modules/Grounding/store/useGroundingStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { StyledConfirmModal } from './RecallModal.styled'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { formatDate } from 'utils/dateUtils'\r\nimport { ISystemSetting } from 'types/baseTypes'\r\n\r\ninterface IProps {\r\n show: boolean\r\n events?: {\r\n onClose: any\r\n setShowModal?: any\r\n handleAcknowledgedConfirm?: any\r\n }\r\n}\r\n\r\nconst RecallModal = ({ show, events }: IProps) => {\r\n const [groundingData] = useGroundingStore((state) => [state.groundingData], shallow)\r\n const [getLocalText] = useGlobalStore((state) => [state.getLocalText])\r\n const openRecallCampaignID = getLocalText('OPEN_RECALL_CAMPAIGN_ID', 'Open Recall Campaign ID')\r\n const openRecallEffectiveDate = getLocalText('OPEN_RECALL_EFFECTIVE_DATE', 'Effective Date')\r\n const openRecallDetails = getLocalText('OPEN_RECALL_DETAILS', 'Recall Details')\r\n const groundingOpenRecallClearingMessage = getLocalText(\r\n 'GROUNDING_OPEN_RECALL_CLEARING_MESSAGE',\r\n 'Note: The open recall must be cleared before retailing'\r\n )\r\n const { getFeatureToggle } = useGlobalStore()\r\n const showRecallAcknowledgement = getFeatureToggle('RecallAcknowledgement') as string\r\n\r\n return (\r\n events.onClose()}\r\n backdrop={Number(showRecallAcknowledgement) === 1 ? 'static' : true}\r\n centered\r\n >\r\n \r\n
\r\n
\r\n {Number(showRecallAcknowledgement) !== 1 && (\r\n \r\n )}\r\n
\r\n {'Open Recall - '}\r\n {groundingData?.VIN}\r\n
\r\n
\r\n
\r\n {groundingData?.RecallCollection &&\r\n groundingData?.RecallCollection.RecallDetails &&\r\n groundingData?.RecallCollection.RecallDetails.map((detail, index) => (\r\n
\r\n
\r\n \r\n {openRecallCampaignID}: {detail.OpenRecallCampaignID}\r\n \r\n
\r\n {detail.RecallEffectiveDate !== undefined && detail.RecallEffectiveDate && (\r\n
\r\n {openRecallEffectiveDate}:\r\n {formatDate(detail.RecallEffectiveDate, 'MM/dd/yyyy')}\r\n
\r\n )}\r\n {detail.RecallDetails !== undefined && detail.RecallDetails && detail.RecallDetails !== '' && (\r\n
\r\n {openRecallDetails}: {detail.RecallDetails}\r\n
\r\n )}\r\n
\r\n ))}\r\n
{groundingOpenRecallClearingMessage}
\r\n {Number(showRecallAcknowledgement) === 1 && (\r\n
\r\n \r\n
\r\n )}\r\n
\r\n
\r\n \r\n )\r\n}\r\n\r\nexport default RecallModal\r\n","import DividerWidthText from 'components/Grounding/DividerWidthText'\r\nimport GroundingVehicleDetails from 'components/Grounding/GroundingVehicleDetails'\r\nimport { Field, Form, Formik, FormikProps, FormikValues, useFormikContext } from 'formik'\r\nimport { useEffect, useMemo, useRef, useState } from 'react'\r\nimport { Col, Row, Form as Checkbox, Button, Alert } from 'react-bootstrap'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { faPencilAlt, faPlus } from '@fortawesome/free-solid-svg-icons'\r\nimport { FormControl as Input } from 'react-bootstrap'\r\nimport { DispositionOption, IGroundingForm, groundingValueValidateSchema } from 'types/Grounding/groundingTypes'\r\nimport {\r\n Campaign,\r\n DropDownGroup,\r\n GroundingDispositionData,\r\n GroundingIndication,\r\n LocationDropDown\r\n} from '../../types/Grounding/GroundingResult'\r\nimport { DropdownList } from 'layouts/DropdownList'\r\nimport {\r\n ERROR_ODOMETER_INVALID_INPUT,\r\n GENERAL_ERROR_MESSAGE,\r\n GND_DISPOSITION_PURCHASE_CONFIRM,\r\n GND_DISPOSITION_RETURN_CONFIRM,\r\n RecallDetailStatus\r\n} from 'common/constants'\r\nimport {\r\n StyledDatePickerWithIcon,\r\n StyledGroundingAdditional,\r\n StyledGroundingItem,\r\n StyledGroundingOdometer,\r\n StyledGroundingOption,\r\n StyledGroundingOptions,\r\n StyledGroundingReview,\r\n StyledLabelRequired\r\n} from './GroundingOptions.styled'\r\nimport { GroundingConfirmModal } from 'components/Grounding/GroundingConfirmModal'\r\nimport DateTimePicker from 'components/DateTimePicker'\r\nimport { addDays } from 'utils/dateUtils'\r\nimport { Calendar } from 'icons/Calendar'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { AddressModal } from 'components/Grounding/AddressModal'\r\nimport { IAddress } from 'types/accountTypes'\r\nimport { saveAddress } from 'apis/userApis'\r\nimport shallow from 'zustand/shallow'\r\nimport { useGroundingStore } from './store/useGroundingStore'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport RecallModal from 'components/Grounding/RecallModal'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { ISystemSetting } from 'types/baseTypes'\r\nimport { GroundingRenderStep } from './store/RenderStep'\r\nimport { useGroundingActionStore } from './store/useGroundingActionStore'\r\n\r\ninterface IProps {\r\n setShowCancelModal: (data: boolean) => void\r\n}\r\n\r\nconst GroundingOptions = ({ setShowCancelModal }: IProps) => {\r\n const [\r\n groundingData,\r\n setGroundingData,\r\n setShowTerms,\r\n alreadyConfirmRecall,\r\n setAlreadyConfirmRecall,\r\n alreadyConfirmGeneralModal,\r\n setAlreadyConfirmGeneralModal\r\n ] = useGroundingStore(\r\n (state) => [\r\n state.groundingData,\r\n state.setGroundingData,\r\n state.setShowTerms,\r\n state.alreadyConfirmRecall,\r\n state.setAlreadyConfirmRecall,\r\n state.alreadyConfirmGeneralModal,\r\n state.setAlreadyConfirmGeneralModal\r\n ],\r\n shallow\r\n )\r\n const [setActiveStep, isSubmit, setIsSubmit] = useGroundingActionStore(\r\n (state) => [state.setActiveStep, state.isSubmit, state.setIsSubmit],\r\n shallow\r\n )\r\n const [isValidate, setIsValidate] = useState(isSubmit)\r\n const { CurrentBuyerID } = useGlobalStore((state) => state.userClaims)\r\n const { getSystemSetting } = useGlobalStore()\r\n const [getLocalText] = useGlobalStore((state) => [state.getLocalText])\r\n const vinValidationList = getSystemSetting('VIN3_VALIDATION') as ISystemSetting\r\n const initialGroundingValue = {\r\n vehicleReturnDate: groundingData.vehicleReturnDate && new Date(groundingData.vehicleReturnDate),\r\n currentVIN: '',\r\n odometerReading: groundingData?.odometerReading.toString(),\r\n confirmOdometerReading: groundingData?.odometerConfirm.toString(),\r\n newVIN: groundingData?.newLeaseVIN,\r\n newBrand: groundingData?.newVehicleBrand,\r\n requiresNewVIN: groundingData?.requiresNewVin,\r\n requiresNewVINNotBrand: groundingData?.requiresNewVINNotBrand,\r\n requiresNewVINForCampaign: groundingData?.requiresNewVINForCampaign,\r\n vinValidationList: vinValidationList,\r\n campaign: groundingData.SelectedCampaignId\r\n }\r\n const [isLoading, setIsLoading] = useState(false)\r\n const [formValues, setFormValues] = useState(null)\r\n const [formErrors, setFormErrors] = useState(null)\r\n const [attributesValue, setAttributesValue] = useState(groundingData?.attributes)\r\n const [odometerOptionSelected, setOdometerOptionSelected] = useState(groundingData?.odometerOptionSelected)\r\n const [performPurchase, setPerformPurchase] = useState(\r\n groundingData?.performPurchase !== undefined ? groundingData?.performPurchase : true\r\n )\r\n const [isInvalidNewVIN, setIsInvalidNewVIN] = useState(false)\r\n\r\n const [initValue, setInitValue] = useState(initialGroundingValue)\r\n const [showCreditConfirmModal, setShowCreditConfirmModal] = useState(false)\r\n let minMilesValue = groundingData?.MinMiles ?? 0\r\n if (\r\n groundingData?.MinMiles !== undefined &&\r\n groundingData?.MinMiles > 0 &&\r\n groundingData?.MinMiles < groundingData?.CRMileage\r\n ) {\r\n minMilesValue = 0\r\n }\r\n const maxMilesValue = groundingData?.MaxMiles ?? 0\r\n const minOdometerValue = groundingData?.MinFinalMileage ? groundingData?.MinFinalMileage - 1 : 0\r\n const maxOdometerValue = groundingData?.MaxFinalMileage ? groundingData?.MaxFinalMileage + 1 : 0\r\n const [isEditAddress, setIsEditAddress] = useState(false)\r\n const [isSaveAddressToBuyer, setIsSaveAddressToBuyer] = useState(true)\r\n const [locationSelected, setLocationSelected] = useState(\r\n groundingData?.selectedAddress === 0 ? groundingData?.locations[0].ID : groundingData?.selectedAddress\r\n )\r\n const [initLocations, setInitLocations] = useState(\r\n groundingData?.initLocations === undefined ? groundingData?.locations.slice(0, -1) : groundingData?.initLocations\r\n )\r\n const [indicationOptionSelected, setIndicationOptionSelected] = useState(\r\n groundingData?.indications.find((x) => x.ID === groundingData?.selectedIndication) ?? null\r\n )\r\n const [isLowerMileageLastInspection, setIsLowerMileageLastInspection] = useState(false)\r\n const [dispositionsValue, setDispositionsValue] = useState(groundingData?.dispositions)\r\n const [groundingDispositionSelected, setGroundingDispositionSelected] = useState(\r\n groundingData?.groundingDispositionSelected\r\n )\r\n const [selectedDispostionID, setSelectedDispostionID] = useState(groundingData?.selectedDisposition)\r\n const [alertMessage] = useState(groundingData?.alertMessage)\r\n const [confirmText, setConfirmText] = useState('')\r\n const [isOpenRecall, setIsOpenRecall] = useState(false)\r\n\r\n const [currentPrice, setCurrentPrice] = useState(groundingData?.purchasePrice)\r\n const [currentPriceString, setCurrentPriceString] = useState(groundingData?.purchasePriceString)\r\n const [encryptedPurchasePrice, setEncryptedPurchasePrice] = useState(groundingData?.encryptedPurchasePrice)\r\n const [buyerFee, setBuyerFee] = useState(groundingData?.buyerFee)\r\n const [buyerFeeString, setBuyerFeeString] = useState(groundingData?.buyerFeeString)\r\n const [payoffAuthorizationCompleted, setPayoffAuthorizationCompleted] = useState(\r\n groundingData?.payoffAuthorizationCompleted !== undefined ? groundingData?.payoffAuthorizationCompleted : true\r\n )\r\n const [selectedCampaignId, setSelectedCampaignId] = useState(groundingData?.SelectedCampaignId)\r\n const [selectedCampaign, setSelectedCampaign] = useState(groundingData?.SelectedCampaign)\r\n const [validCampaignsForGrounding, setValidCampaignsForGrounding] = useState(\r\n groundingData?.validCampaignsForGrounding ?? []\r\n )\r\n\r\n const [showRecallModal, setShowRecallModal] = useState(false)\r\n const [showGeneralModal, setShowGeneralModal] = useState(false)\r\n const [showConfirmOdometer, setShowConfirmOdometer] = useState(false)\r\n const [showAddressModal, setShowAddressModal] = useState(false)\r\n\r\n const [showErrorMessage, setShowErrorMessage] = useState(false)\r\n const [today, setToday] = useState(null)\r\n const confirmationText = getLocalText(\r\n 'Confirm_Payoff_Authorization',\r\n 'The customer’s credit in the amount of %AMOUNT% has been applied to the purchase price of the vehicle. Is the Payoff Authorization form complete?'\r\n )\r\n\r\n const confirmOdoStatement = getLocalText(\r\n 'Confirm_Odo_Statement',\r\n 'YOU HAVE INDICATED THAT THERE IS A PROBLEM WITH THE ODOMETER OF THIS VEHICLE. AS A RESULT, THIS VEHICLE WILL NOT BE MADE AVAILABLE FOR SALE. IS THIS CORRECT?'\r\n )\r\n const history = useHistory()\r\n const formRef = useRef>(null)\r\n const [isMileageOptionNeedConfirm, setIsMileageOptionNeedConfirm] = useState(false)\r\n\r\n useEffect(() => {\r\n let initSchemaValue = initValue\r\n initSchemaValue.currentVIN = groundingData?.VIN\r\n if (groundingData?.MaxBackdateDays === 0 || groundingData?.MaxBackdateDays === undefined) {\r\n initSchemaValue.vehicleReturnDate = new Date(groundingData?.groundingDate)\r\n }\r\n setInitValue(initSchemaValue)\r\n }, [groundingData?.VIN, initLocations, initValue])\r\n\r\n useEffect(() => {\r\n if (groundingData?.dispositions.length === 1 && groundingDispositionSelected === undefined) {\r\n setGroundingDispositionSelected(groundingData?.dispositions[0])\r\n groundingData.purchasePrice = groundingData?.dispositions[0].PurchasePrice\r\n groundingData.purchasePriceString = groundingData?.dispositions[0].PurchasePriceString\r\n setGroundingData(groundingData)\r\n setCurrentPrice(groundingData?.dispositions[0].PurchasePrice)\r\n setCurrentPriceString(groundingData?.dispositions[0].PurchasePriceString)\r\n setEncryptedPurchasePrice(groundingData?.dispositions[0].EncryptedPurchasePrice)\r\n setBuyerFee(groundingData?.dispositions[0].BuyerFee)\r\n setBuyerFeeString(groundingData?.dispositions[0].BuyerFeeString)\r\n }\r\n\r\n // Recall logic\r\n const hasOpenRecall =\r\n groundingData?.RecallCollection &&\r\n Number(groundingData?.RecallCollection?.RecallStatusType) === RecallDetailStatus.HasOpenRecall\r\n setIsOpenRecall(hasOpenRecall)\r\n if (\r\n alertMessage !== undefined &&\r\n alertMessage !== null &&\r\n (alreadyConfirmGeneralModal === false || alreadyConfirmGeneralModal === undefined)\r\n ) {\r\n setConfirmText(alertMessage)\r\n setShowGeneralModal(true)\r\n } else {\r\n if (hasOpenRecall && (alreadyConfirmRecall === false || alreadyConfirmRecall === undefined)) {\r\n setShowRecallModal(true)\r\n }\r\n }\r\n\r\n // handleCampaignData(new Date(groundingData?.vehicleReturnDate))\r\n\r\n //Terms and Conditions link logic\r\n const link = document.getElementById('termsLink')\r\n if (link) {\r\n link.addEventListener('click', handleClick)\r\n }\r\n\r\n return () => {\r\n // Cleanup function to remove event listener\r\n if (link) {\r\n link.removeEventListener('click', handleClick)\r\n }\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!isSubmit) return\r\n handleReviewSubmitButtonClicked()\r\n if (formRef.current) {\r\n formRef.current.handleSubmit()\r\n }\r\n }, [isSubmit])\r\n\r\n const showIndications = useMemo(() => {\r\n return (\r\n groundingData?.indications.length > 0 &&\r\n (groundingDispositionSelected?.ID === DispositionOption.LESSEE_RETURN ||\r\n groundingDispositionSelected?.ID === DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT) &&\r\n !selectedCampaign?.IsPullAhead\r\n )\r\n }, [groundingData, groundingDispositionSelected, selectedCampaign])\r\n\r\n const hasError = useMemo(\r\n () =>\r\n Boolean(\r\n groundingDispositionSelected === null ||\r\n groundingDispositionSelected === undefined ||\r\n (showIndications && indicationOptionSelected === null) ||\r\n odometerOptionSelected < 0 ||\r\n odometerOptionSelected === undefined ||\r\n attributesValue.some(\r\n (x) => x.IsRequired && (x.selectedID === undefined || x.selectedID === null || x.selectedID?.ID < 0)\r\n ) ||\r\n locationSelected === 0 ||\r\n selectedCampaignId === -1\r\n ),\r\n [\r\n odometerOptionSelected,\r\n groundingDispositionSelected,\r\n locationSelected,\r\n showIndications,\r\n indicationOptionSelected,\r\n attributesValue,\r\n selectedCampaignId\r\n ]\r\n )\r\n\r\n const handleClick = (event) => {\r\n event.preventDefault() // Prevent default navigation\r\n setShowTerms(true)\r\n }\r\n\r\n const isCheckMaximumOdometer = 1\r\n\r\n const resetPriceForDispOption16And17 = () => {\r\n const newDispositions = [...dispositionsValue]\r\n newDispositions.forEach((disposition) => {\r\n if (\r\n disposition.ID === DispositionOption.LESSEE_PURCHASE ||\r\n disposition.ID === DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT\r\n ) {\r\n disposition.PurchasePrice = disposition.CopyPurchasePrice\r\n disposition.PurchasePriceString = disposition.CopyPurchasePriceString\r\n }\r\n })\r\n setDispositionsValue(newDispositions)\r\n }\r\n\r\n const handleConfirmPayoff = () => {\r\n resetPriceForDispOption16And17()\r\n if (groundingDispositionSelected.PurchasePrice) {\r\n groundingData.purchasePrice = groundingDispositionSelected.PurchasePrice\r\n groundingData.purchasePriceString = groundingDispositionSelected.PurchasePriceString\r\n setGroundingData(groundingData)\r\n setCurrentPrice(groundingDispositionSelected.PurchasePrice)\r\n setCurrentPriceString(groundingDispositionSelected.PurchasePriceString)\r\n setEncryptedPurchasePrice(groundingDispositionSelected.EncryptedPurchasePrice)\r\n setBuyerFee(groundingDispositionSelected.BuyerFee)\r\n setBuyerFeeString(groundingDispositionSelected.BuyerFeeString)\r\n }\r\n setShowCreditConfirmModal(false)\r\n setPayoffAuthorizationCompleted(true)\r\n }\r\n\r\n const handleRejectPayoff = () => {\r\n let newDispositions = [...dispositionsValue]\r\n newDispositions.forEach((disposition) => {\r\n if (disposition.ID === groundingDispositionSelected.ID) {\r\n disposition.PurchasePrice = disposition.CreditPurchasePrice\r\n disposition.PurchasePriceString = disposition.CreditPurchasePriceString\r\n } else {\r\n disposition.PurchasePrice = disposition.CopyPurchasePrice\r\n disposition.PurchasePriceString = disposition.CopyPurchasePriceString\r\n }\r\n })\r\n setDispositionsValue(newDispositions)\r\n groundingData.purchasePrice = groundingDispositionSelected.PurchasePrice\r\n groundingData.purchasePriceString = groundingDispositionSelected.PurchasePriceString\r\n setGroundingData(groundingData)\r\n setCurrentPrice(groundingDispositionSelected.PurchasePrice)\r\n setCurrentPriceString(groundingDispositionSelected.PurchasePriceString)\r\n setEncryptedPurchasePrice(groundingDispositionSelected.EncryptedPurchasePrice)\r\n setBuyerFee(groundingDispositionSelected.BuyerFee)\r\n setBuyerFeeString(groundingDispositionSelected.BuyerFeeString)\r\n setShowCreditConfirmModal(false)\r\n setPayoffAuthorizationCompleted(false)\r\n }\r\n\r\n const handleResetPayoff = () => {\r\n resetPriceForDispOption16And17()\r\n groundingData.purchasePrice = 0\r\n groundingData.purchasePriceString = ''\r\n setGroundingData(groundingData)\r\n setCurrentPrice(0)\r\n setCurrentPriceString('')\r\n setBuyerFee(0)\r\n setBuyerFeeString('')\r\n setGroundingDispositionSelected(null)\r\n setShowCreditConfirmModal(false)\r\n setPayoffAuthorizationCompleted(true)\r\n }\r\n\r\n const handleGroundingOptionChange = (dispositonOptionIndex: number) => {\r\n setIndicationOptionSelected(null)\r\n const currentDispositon = groundingData?.dispositions[dispositonOptionIndex]\r\n setSelectedDispostionID(currentDispositon.ID)\r\n setGroundingDispositionSelected(currentDispositon)\r\n groundingData.purchasePrice = currentDispositon.PurchasePrice\r\n groundingData.purchasePriceString = currentDispositon.PurchasePriceString\r\n groundingData.selectedNoSignReason = 0\r\n for (const signatureType of groundingData?.signatureTypes) {\r\n signatureType.SelectedNoSignReason = 0\r\n }\r\n setGroundingData(groundingData)\r\n setCurrentPrice(currentDispositon.PurchasePrice)\r\n setCurrentPriceString(currentDispositon.PurchasePriceString)\r\n setEncryptedPurchasePrice(currentDispositon.EncryptedPurchasePrice)\r\n setBuyerFee(currentDispositon.BuyerFee)\r\n setBuyerFeeString(currentDispositon.BuyerFeeString)\r\n if (groundingData?.creditBalanceFlag === 'N') {\r\n return\r\n }\r\n if (\r\n (currentDispositon.ID === DispositionOption.LESSEE_PURCHASE ||\r\n currentDispositon.ID === DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT) &&\r\n groundingData\r\n ) {\r\n setShowCreditConfirmModal(true)\r\n } else {\r\n resetPriceForDispOption16And17()\r\n setPayoffAuthorizationCompleted(false)\r\n }\r\n }\r\n\r\n const handleIndicationOptionChange = (indicationOptionId: number) => {\r\n setIndicationOptionSelected(groundingData?.indications.find((x) => x.ID === indicationOptionId))\r\n }\r\n\r\n const handleAttributeChange = (id: number, index: number) => {\r\n const newAttributes = attributesValue.map((attribute, idx) => {\r\n if (idx === index) {\r\n return {\r\n ...attribute,\r\n selectedID: attribute.attributeSelections.find((x) => x.ID === id)\r\n }\r\n }\r\n return attribute\r\n })\r\n setAttributesValue(newAttributes)\r\n }\r\n\r\n const handleOdometerOptionChange = (odometerOptionId: number) => {\r\n setOdometerOptionSelected(odometerOptionId)\r\n if (\r\n (odometerOptionId === 2 || odometerOptionId === 3) &&\r\n groundingData?.odometerStatements.find((x) => x.ID === odometerOptionId)?.FieldDescription === 'Y'\r\n ) {\r\n setIsMileageOptionNeedConfirm(true)\r\n setPerformPurchase(false)\r\n } else {\r\n setPerformPurchase(true)\r\n }\r\n }\r\n\r\n const handleBlurOdometer = (e: any) => {\r\n const odometerInputValue = e.target.value\r\n\r\n if (\r\n (odometerInputValue !== '' &&\r\n Number(odometerInputValue) > minOdometerValue &&\r\n Number(odometerInputValue) < minMilesValue) ||\r\n (isCheckMaximumOdometer &&\r\n Number(odometerInputValue) < maxOdometerValue &&\r\n Number(odometerInputValue) > maxMilesValue)\r\n ) {\r\n if (Number(odometerInputValue) < groundingData?.CRMileage) {\r\n setIsLowerMileageLastInspection(true)\r\n }\r\n setShowConfirmOdometer(true)\r\n } else {\r\n setShowConfirmOdometer(false)\r\n }\r\n }\r\n\r\n const updateLocations = (address: IAddress, addressDescription: string) => {\r\n setInitLocations((x) =>\r\n x.map((location) => {\r\n if (location.ID === locationSelected) {\r\n return {\r\n ...location,\r\n Description: addressDescription,\r\n Address1: address.AddressLineOne,\r\n Address2: address.AddressLineTwo,\r\n City: address.Town,\r\n State: groundingData?.states?.find((x) => x.ID === address.StateId)?.FieldDescription,\r\n StateCode: groundingData?.states?.find((x) => x.ID === address.StateId)?.FieldDescription,\r\n Zip: address.PostCode\r\n }\r\n }\r\n return location\r\n })\r\n )\r\n }\r\n\r\n const addLocations = (address: IAddress, addressDescription: string, addressId: number) => {\r\n setInitLocations((currentList) => [\r\n {\r\n ID: addressId,\r\n Description: addressDescription,\r\n Address1: address.AddressLineOne,\r\n Address2: address.AddressLineTwo,\r\n City: address.Town,\r\n State: groundingData?.states?.find((x) => x.ID === address.StateId)?.Description,\r\n StateCode: groundingData?.states?.find((x) => x.ID === address.StateId)?.FieldDescription,\r\n Zip: address.PostCode,\r\n AddressTypeID: address.AddressTypeId\r\n },\r\n ...currentList\r\n ])\r\n setLocationSelected(addressId)\r\n }\r\n\r\n const handleShowAddressModal = (isEdit: boolean) => {\r\n setShowAddressModal(true)\r\n setIsEditAddress(isEdit)\r\n }\r\n\r\n const handleSaveAddress = async (address: IAddress) => {\r\n try {\r\n setShowAddressModal(false)\r\n setIsLoading(true)\r\n\r\n const result = await saveAddress({\r\n Address: address,\r\n SaveToBuyer: isSaveAddressToBuyer\r\n })\r\n\r\n if (result > 0) {\r\n const addressDescription =\r\n address.AddressLineOne +\r\n `${address.AddressLineTwo !== '' ? ', ' + address.AddressLineTwo : ''}` +\r\n ', ' +\r\n address.Town +\r\n ', ' +\r\n groundingData?.states?.find((x) => x.ID === address.StateId)?.FieldDescription +\r\n ' ' +\r\n address.PostCode\r\n\r\n if (isEditAddress && address.AddressId != 0) {\r\n updateLocations(address, addressDescription)\r\n } else {\r\n addLocations(address, addressDescription, result)\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error)\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n const handleReviewSubmitButtonClicked = () => {\r\n setIsValidate(true)\r\n if (\r\n hasError === true ||\r\n formValues?.vehicleReturnDate === null ||\r\n formValues?.odometerReading <= minOdometerValue ||\r\n formErrors?.newVIN !== null ||\r\n selectedCampaignId === -1 ||\r\n (isCheckMaximumOdometer && Number(formValues?.odometerReading) >= maxOdometerValue)\r\n ) {\r\n setShowErrorMessage(true)\r\n window.scrollTo(0, 0)\r\n setIsSubmit(false)\r\n }\r\n }\r\n\r\n const handleReviewSubmit = (values: any) => {\r\n if (\r\n hasError === true ||\r\n values.vehicleReturnDate === null ||\r\n Number(values.odometerReading) <= minOdometerValue ||\r\n (isCheckMaximumOdometer && Number(values.odometerReading) >= maxOdometerValue)\r\n ) {\r\n return\r\n }\r\n updateGroundingData(values)\r\n setActiveStep(GroundingRenderStep.GRD_TURN_IN)\r\n setIsSubmit(false)\r\n setIsLoading(false)\r\n }\r\n\r\n const updateGroundingData = (formValues: IGroundingForm) => {\r\n if (groundingData) {\r\n let newGroundingData = JSON.parse(JSON.stringify(groundingData))\r\n newGroundingData.DealerID = CurrentBuyerID\r\n newGroundingData.buyerAddress = groundingData.locations.find((x) => x.ID === locationSelected)?.Address1 ?? ''\r\n newGroundingData.buyerAddress2 = groundingData.locations.find((x) => x.ID === locationSelected)?.Address2 ?? ''\r\n newGroundingData.buyerCity = groundingData.locations.find((x) => x.ID === locationSelected)?.City ?? ''\r\n newGroundingData.buyerState = groundingData.locations.find((x) => x.ID === locationSelected)?.State ?? ''\r\n newGroundingData.buyerZip = groundingData.locations.find((x) => x.ID === locationSelected)?.Zip ?? ''\r\n newGroundingData.selectedAddress = locationSelected\r\n newGroundingData.initLocations = initLocations\r\n newGroundingData.selectedOdometerStatement = groundingData.odometerStatements.find(\r\n (x) => x.ID === odometerOptionSelected\r\n )?.Description\r\n newGroundingData.odometerOptionSelected = odometerOptionSelected\r\n newGroundingData.vehicleReturnDate = formValues.vehicleReturnDate.toLocaleDateString()\r\n newGroundingData.odometerReading = Number(formValues.odometerReading)\r\n newGroundingData.odometerConfirm = Number(formValues.confirmOdometerReading)\r\n newGroundingData.newLeaseVIN = formValues.newVIN\r\n newGroundingData.newVehicleBrand = formValues.newBrand\r\n\r\n newGroundingData.selectedIndication = indicationOptionSelected?.ID\r\n newGroundingData.groundingDispositionSelected = groundingDispositionSelected\r\n newGroundingData.selectedDisposition = selectedDispostionID\r\n newGroundingData.attributes = attributesValue\r\n newGroundingData.payoffAuthorizationCompleted = payoffAuthorizationCompleted\r\n if (groundingData?.dispositions.find((x) => x.ID === DispositionOption.DEALER_INVENTORY_PURCHASE)) {\r\n newGroundingData.canPurchaseVehicleInGESaleChannel = true\r\n } else {\r\n newGroundingData.canPurchaseVehicleInGESaleChannel = false\r\n }\r\n newGroundingData.performPurchase = performPurchase\r\n newGroundingData.purchasePrice = currentPrice\r\n newGroundingData.purchasePriceString = currentPriceString\r\n newGroundingData.encryptedPurchasePrice = encryptedPurchasePrice\r\n newGroundingData.buyerFee = buyerFee\r\n newGroundingData.buyerFeeString = buyerFeeString\r\n newGroundingData.SelectedCampaignId = selectedCampaignId\r\n newGroundingData.SelectedCampaign = selectedCampaign\r\n newGroundingData.validCampaignsForGrounding = validCampaignsForGrounding\r\n newGroundingData.requiresNewVin = formValues.requiresNewVIN\r\n newGroundingData.requiresNewVINNotBrand = formValues.requiresNewVINNotBrand\r\n newGroundingData.requiresNewVINForCampaign = formValues.requiresNewVINForCampaign\r\n setGroundingData(newGroundingData)\r\n }\r\n }\r\n\r\n const handleCampaignData = (returnDate: string) => {\r\n let hasData: boolean = false\r\n setValidCampaignsForGrounding([])\r\n setSelectedCampaignId(0)\r\n if (groundingData?.Campaigns && groundingData?.Campaigns.length > 0) {\r\n groundingData?.Campaigns.forEach((campaign) => {\r\n const startDate = new Date(campaign.StartDate)\r\n const endDate = new Date(campaign.EndDate)\r\n const newReturnDate = new Date(returnDate)\r\n const gracePeriodDate = addDays(endDate, groundingData?.gracePeriod)\r\n const currentDate = new Date()\r\n if (newReturnDate >= startDate && newReturnDate <= endDate) {\r\n if (currentDate >= startDate && currentDate <= gracePeriodDate) {\r\n hasData = true\r\n setValidCampaignsForGrounding((prev) => {\r\n return [...prev, campaign]\r\n })\r\n }\r\n }\r\n })\r\n if (hasData) {\r\n setSelectedCampaignId(-1)\r\n setValidCampaignsForGrounding((prev) => {\r\n return [...prev, groundingData?.Campaigns[groundingData?.Campaigns.length - 1]]\r\n })\r\n }\r\n }\r\n }\r\n\r\n const handleCampaignOptionChange = (campaignID: number) => {\r\n setSelectedCampaignId(campaignID)\r\n setToday(null)\r\n setSelectedCampaign(groundingData?.Campaigns.find((campaign) => campaign.ID === campaignID))\r\n }\r\n\r\n const computedAcknowledgeBlock = function (textToUpdate: string, currentPurchasePriceString: string) {\r\n return textToUpdate && textToUpdate.replace('%AMOUNT%', currentPurchasePriceString)\r\n }\r\n\r\n const saveFormErrors = (values) => {\r\n setFormErrors(values)\r\n }\r\n\r\n const FormErrorContext = () => {\r\n const formik = useFormikContext()\r\n useEffect(() => {\r\n saveFormErrors(formik.errors)\r\n setFormValues(formik.values)\r\n }, [formik.errors, formik.values])\r\n return null\r\n }\r\n\r\n return (\r\n \r\n {isLoading && }\r\n \r\n {\r\n setFormValues(values)\r\n handleReviewSubmit(values)\r\n }}\r\n >\r\n {(props) => (\r\n \r\n )}\r\n \r\n {showAddressModal && (\r\n x.ID === locationSelected) : null}\r\n isEditAddress={isEditAddress}\r\n stateList={groundingData?.states}\r\n show={showAddressModal}\r\n events={{\r\n onClose: () => setShowAddressModal(false),\r\n handleSaveAddress: handleSaveAddress,\r\n setIsSaveAddressToBuyer: setIsSaveAddressToBuyer\r\n }}\r\n >\r\n )}\r\n {showGeneralModal && (\r\n {\r\n setShowGeneralModal(false)\r\n history.push('/')\r\n },\r\n setShowModal: setShowGeneralModal,\r\n handleAcknowledgedConfirm: () => {\r\n setShowGeneralModal(false)\r\n if (isOpenRecall) {\r\n setShowRecallModal(true)\r\n }\r\n setAlreadyConfirmGeneralModal(true)\r\n }\r\n }}\r\n isShowHeader={false}\r\n isShowButton={true}\r\n isShowYesButton={false}\r\n isShowNoButton={false}\r\n isBackdropStatic={true}\r\n >\r\n )}\r\n {showRecallModal && (\r\n {\r\n setShowRecallModal(false)\r\n setAlreadyConfirmRecall(true)\r\n }\r\n }}\r\n />\r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default GroundingOptions\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\n\r\nconst StyleGroundingResults = styled.div``\r\nexport const StyleGroundingResult = styled.div`\r\n padding: 2rem 3rem 3rem;\r\n border-radius: 3px;\r\n box-shadow: 0px -1px 2px rgb(0 0 0 / 15%), 2px 2px 2px rgb(0 0 0 / 25%);\r\n margin: 5px 0 30px 0;\r\n display: block;\r\n background-color: white;\r\n\r\n > p:first-child {\r\n text-align: end;\r\n font-weight: 600;\r\n font-size: 16px;\r\n margin-bottom: 10px;\r\n }\r\n\r\n .alert {\r\n max-width: 100% !important;\r\n }\r\n\r\n .title-result {\r\n color: ${({ theme }) => theme.colors.successColor};\r\n text-align: center;\r\n }\r\n\r\n .document-form {\r\n margin-top: 3rem;\r\n margin-bottom: 8rem;\r\n button {\r\n width: inherit;\r\n min-width: 100px;\r\n }\r\n\r\n .download-btn {\r\n width: 104%;\r\n }\r\n\r\n @media (max-width: ${gridBreakPoints.sm}) {\r\n .download-btn {\r\n transform: translateX(-12px);\r\n }\r\n }\r\n }\r\n\r\n .email-input,\r\n .ground-another-vin {\r\n .send-button {\r\n width: inherit;\r\n }\r\n display: flex;\r\n label {\r\n transform: translateY(4px);\r\n font-weight: bold;\r\n }\r\n }\r\n`\r\nexport default StyleGroundingResults\r\n","import { fetchAsync, postAsync } from 'common/fetch'\r\nimport { IEmailRtn } from 'types/Grounding/GroundingRequest'\r\nimport { GroundingReturn } from 'types/Grounding/GroundingResult'\r\n\r\nexport const getGroundingConfigurationByVIN = (vin: string) => {\r\n return postAsync(`/api/grounding/GetGroundingConfigurationByVIN`, {\r\n body: vin\r\n })\r\n}\r\n\r\nexport const saveGrounding = (req: GroundingReturn) => {\r\n return postAsync(`/api/grounding/SaveGrounding`, {\r\n body: req\r\n })\r\n}\r\n\r\nexport const checkGroundingService = () => {\r\n return fetchAsync(`/api/grounding/IsServiceRunning`)\r\n}\r\n\r\nexport const sendEmail = (req: IEmailRtn) => {\r\n return postAsync(`/api/grounding/SendEmailGroundingPDFByVIN`, {\r\n body: req\r\n })\r\n}\r\n","export const downloadURI = (url: string) => {\r\n let link = document.createElement('a')\r\n link.href = url\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n}\r\n","import GroundingVehicleDetails from 'components/Grounding/GroundingVehicleDetails'\r\nimport { useEffect, useState } from 'react'\r\nimport StyleGroundingResults, { StyleGroundingResult } from './GroundingResult.styled'\r\nimport DividerWidthText from 'components/Grounding/DividerWidthText'\r\nimport { Alert, Button, Col, Form, InputGroup, Row } from 'react-bootstrap'\r\nimport shallow from 'zustand/shallow'\r\nimport { useGroundingStore } from './store/useGroundingStore'\r\nimport { faTimes } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport { Formik, useFormik } from 'formik'\r\nimport { sendEmail } from 'apis/groundingApis'\r\nimport { IEmailRtn } from 'types/Grounding/GroundingRequest'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { Rules } from 'common/rules'\r\nimport { downloadURI } from 'utils/exportFileUtil'\r\nimport * as Yup from 'yup'\r\nimport { DocumentType, DocumentTypeEnum, SessionStorageKey } from 'common/constants'\r\nimport { OverlayLoader } from 'components/Loader'\r\n\r\ninterface MessageType {\r\n content: string\r\n type: string\r\n}\r\ninterface IDocumentType {\r\n id?: number\r\n description?: string\r\n}\r\ninterface DocumentFormProps {\r\n docType?: IDocumentType\r\n VIN: string\r\n vehicleInstanceId: number\r\n allowOffer?: boolean\r\n showMakeOfferOrPurchase?: boolean\r\n isPurchase?: boolean\r\n setSuccess: () => void\r\n setError: (message: string) => void\r\n}\r\n\r\nconst GroundingResult = () => {\r\n const [groundingData] = useGroundingStore((state) => [state.groundingData], shallow)\r\n const [isInRule] = useGlobalStore((state) => [state.isInRule], shallow)\r\n const [isLoading, setIsLoading] = useState(false)\r\n\r\n const [showMessage, setShowMessage] = useState(false)\r\n const [showVehMandatory, setShowVehMandatory] = useState(groundingData?.isVehicleMandatory)\r\n const [message, setMessage] = useState({\r\n content: '',\r\n type: 'success'\r\n })\r\n const [hasSaveGroundingError, setHasSaveGroundingError] = useState(false)\r\n\r\n const isPurchase =\r\n groundingData?.purchasePriceString !== undefined &&\r\n groundingData?.purchasePriceString !== null &&\r\n groundingData?.purchasePriceString !== '' &&\r\n groundingData?.performPurchase === true\r\n const allowPurchase = isInRule(Rules.VIEW_DASHBOARD_GROUNDING_STATUS)\r\n const showMakeOfferOrPurchase =\r\n allowPurchase &&\r\n groundingData?.selectedIndication &&\r\n groundingData?.paymentTypes.length > 0 &&\r\n (groundingData?.purchasePriceString === undefined || groundingData?.purchasePriceString !== '$0') &&\r\n !isPurchase &&\r\n groundingData?.canPurchaseVehicleInGESaleChannel\r\n\r\n useEffect(() => {\r\n window.sessionStorage.removeItem(SessionStorageKey.GROUND_VIN)\r\n if (groundingData?.ErrorMessage !== '' && groundingData?.ErrorMessage !== undefined) {\r\n handleMessage(false, groundingData?.ErrorMessage)\r\n setHasSaveGroundingError(true)\r\n }\r\n }, [])\r\n\r\n const handleMessage = (status: boolean, content: string = 'Email Sent') => {\r\n if (status) {\r\n setMessage({\r\n content,\r\n type: 'success'\r\n })\r\n setShowMessage(true)\r\n return\r\n }\r\n setMessage({\r\n content,\r\n type: 'danger'\r\n })\r\n setShowMessage(true)\r\n }\r\n\r\n const SubmitGrounding = async (values) => {\r\n sessionStorage.setItem(SessionStorageKey.GROUND_VIN, values.vin)\r\n window.location.href = '/grounding'\r\n }\r\n\r\n const schema = Yup.object({\r\n vin: Yup.string().length(17, 'Must be 17 characters').required('Required')\r\n })\r\n\r\n return (\r\n \r\n {isLoading && }\r\n \r\n \r\n Grounding Completion Date: {groundingData?.groundingDate}
\r\n \r\n {!hasSaveGroundingError && (\r\n \r\n VIN {groundingData?.VIN} has been successfully grounded {isPurchase ? 'and purchased' : ''}\r\n
\r\n )}\r\n {showVehMandatory && (\r\n setShowVehMandatory(false)} dismissible>\r\n {groundingData?.MandatoryOrEligible}\r\n \r\n )}\r\n \r\n {showMessage && (\r\n setShowMessage(false)} dismissible>\r\n {message?.content}\r\n \r\n )}\r\n
\r\n {!hasSaveGroundingError && (\r\n \r\n \r\n \r\n {groundingData?.VehicleDocuments?.map((e) => (\r\n doc.id === e.DocumentTypeID)}\r\n isPurchase={\r\n (isPurchase && e?.DocumentTypeID === DocumentTypeEnum.PURCHASE) ||\r\n e?.DocumentTypeID !== DocumentTypeEnum.PURCHASE\r\n }\r\n allowOffer={groundingData?.AllowOffer}\r\n showMakeOfferOrPurchase={showMakeOfferOrPurchase}\r\n setSuccess={() => {\r\n handleMessage(true)\r\n }}\r\n setError={(message) => {\r\n handleMessage(false, message)\r\n }}\r\n key={e.ID}\r\n />\r\n ))}\r\n
\r\n \r\n
\r\n )}\r\n \r\n \r\n \r\n \r\n {(props) => (\r\n \r\n )}\r\n \r\n \r\n
\r\n \r\n \r\n )\r\n}\r\n\r\nconst DocumentForm = ({\r\n VIN,\r\n vehicleInstanceId,\r\n docType,\r\n isPurchase,\r\n allowOffer,\r\n showMakeOfferOrPurchase,\r\n setSuccess,\r\n setError\r\n}: DocumentFormProps) => {\r\n const handleSendEmail = async (value) => {\r\n const req: IEmailRtn = {\r\n VIN: VIN,\r\n documentType: docType.id,\r\n emailList: value.email\r\n }\r\n if (value.email === '') {\r\n return setError('You must enter one or more email address(es)')\r\n }\r\n const response = await sendEmail(req)\r\n if (response === '') {\r\n setSuccess()\r\n } else {\r\n setError(response)\r\n }\r\n value.email = ''\r\n }\r\n\r\n const formik = useFormik({\r\n initialValues: {\r\n email: ''\r\n },\r\n onSubmit: handleSendEmail\r\n })\r\n\r\n const handleUrl = (id) => {\r\n const url = '/resource/GetGroundingPDFByVIN?VIN=' + VIN + '&type=' + id\r\n downloadURI(url)\r\n }\r\n\r\n return (\r\n <>\r\n {isPurchase && (\r\n \r\n )}\r\n {showMakeOfferOrPurchase && (\r\n <>\r\n \r\n \r\n \r\n\r\n {allowOffer !== undefined && allowOffer === true && (\r\n \r\n )}\r\n
\r\n >\r\n )}\r\n >\r\n )\r\n}\r\n\r\nexport default GroundingResult\r\n","import { gridBreakPoints } from 'common/theme'\r\nimport styled from 'styled-components'\r\nexport const StyledTurnIns = styled.div`\r\n --padding-content: 3rem;\r\n --padding-content-mobile: 2rem;\r\n\r\n .dropdown:focus,\r\n .dropdown:focus-visible,\r\n .dropdown:hover {\r\n box-shadow: none;\r\n }\r\n .dropdown-item.active,\r\n .dropdown-item:focus-visible,\r\n .dropdown-item:hover {\r\n outline: 0;\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n color: #fff;\r\n /* border-bottom: 1px solid ${({ theme }) => theme.colors.InfinitiOnlyColor}; */\r\n }\r\n .dropdown-menu {\r\n box-shadow: 0 0 1px rgba(0, 0, 0, 0.12), 0 1px 1px rgba(0, 0, 0, 0.24);\r\n }\r\n\r\n form {\r\n /* padding: 20px var(--padding-content);\r\n border-radius: 3px;\r\n box-shadow: 0px -1px 2px rgb(0 0 0 / 15%), 2px 2px 2px rgb(0 0 0 / 25%);\r\n margin: 5px 0 30px 0;\r\n display: block;\r\n background-color: white; */\r\n\r\n > p:first-child {\r\n text-align: end;\r\n font-weight: 600;\r\n font-size: 16px;\r\n margin-bottom: 0;\r\n }\r\n }\r\n\r\n button {\r\n margin-left: 0;\r\n padding: 5px 20px;\r\n }\r\n\r\n .error-label {\r\n min-height: 1.8rem;\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-size: 1.2rem !important;\r\n margin-bottom: 0;\r\n margin-top: 10px !important;\r\n font-weight: bold;\r\n }\r\n\r\n .alert {\r\n max-width: 100% !important;\r\n }\r\n\r\n .col-lg-4,\r\n .col-lg-5,\r\n .col-lg-6,\r\n .col-lg-7,\r\n .col-lg-1,\r\n .col-md-6,\r\n .col-md-5,\r\n .col-md-1,\r\n .col-sm-4,\r\n .col-lg-12 {\r\n padding: 0;\r\n }\r\n\r\n .row {\r\n margin-right: 0;\r\n margin-left: 0;\r\n }\r\n\r\n .text-divider {\r\n padding: 0;\r\n margin-top: 15px;\r\n text-transform: uppercase;\r\n\r\n h2 {\r\n color: ${({ theme }) => theme.colors.primary};\r\n font-weight: bold;\r\n }\r\n\r\n :first-child {\r\n margin-top: 0;\r\n }\r\n }\r\n\r\n .right-field,\r\n .left-field {\r\n label {\r\n font-weight: 600;\r\n }\r\n\r\n .col-lg-6 {\r\n padding: 0;\r\n }\r\n }\r\n\r\n .left-field {\r\n padding-right: calc(var(--padding-content) / 2);\r\n }\r\n\r\n .right-field {\r\n padding-left: calc(var(--padding-content) / 2);\r\n }\r\n\r\n .dropdown-container {\r\n height: 30px;\r\n }\r\n\r\n .actual-mileage-warning {\r\n min-height: 1.8rem;\r\n line-height: 1.8rem;\r\n font-size: 15px;\r\n color: red;\r\n margin-bottom: 0;\r\n }\r\n\r\n .odometer-warning {\r\n margin-bottom: 10px;\r\n p:before {\r\n content: '! ';\r\n }\r\n\r\n .odometer-warning-label {\r\n font-size: 15px;\r\n color: red;\r\n text-align: end;\r\n margin: 0;\r\n }\r\n\r\n .form-check {\r\n text-align: end;\r\n\r\n input {\r\n width: 16px;\r\n height: 16px;\r\n cursor: pointer;\r\n }\r\n\r\n label {\r\n cursor: pointer;\r\n font-weight: normal;\r\n }\r\n }\r\n }\r\n`\r\n\r\nexport const StyledTurnInTitle = styled.div`\r\n color: ${({ theme }) => theme.colors.defaultTextColor};\r\n\r\n span {\r\n font-weight: 600;\r\n }\r\n a {\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n cursor: pointer;\r\n }\r\n`\r\nexport const StyledTurnIn = styled.div`\r\n padding: 2rem 3rem 3rem;\r\n border-radius: 3px;\r\n box-shadow: 0px -1px 2px rgb(0 0 0 / 15%), 2px 2px 2px rgb(0 0 0 / 25%);\r\n margin: 5px 0 30px 0;\r\n display: block;\r\n background-color: white;\r\n font-size: 14px;\r\n\r\n > p:first-child {\r\n text-align: end;\r\n font-weight: 600;\r\n font-size: 16px;\r\n margin-bottom: -6px;\r\n }\r\n\r\n span {\r\n line-height: 30px;\r\n }\r\n\r\n .close {\r\n height: 100%;\r\n\r\n span {\r\n line-height: 0;\r\n }\r\n }\r\n\r\n svg {\r\n fill: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n vertical-align: text-bottom;\r\n margin-right: 8px;\r\n }\r\n\r\n .ack-checkbox {\r\n & > label {\r\n text-transform: uppercase;\r\n margin-bottom: 5px;\r\n }\r\n\r\n .checkbox-form {\r\n margin-bottom: 30px;\r\n }\r\n }\r\n\r\n .upper-receipt {\r\n padding-bottom: 0 !important;\r\n }\r\n\r\n .nosign-container {\r\n display: flex;\r\n flex-wrap: wrap;\r\n margin: 80px 0px 20px;\r\n\r\n .nosign-dropdown {\r\n display: flex;\r\n flex-direction: column;\r\n\r\n .error-label {\r\n margin-left: 14px;\r\n }\r\n }\r\n .dropdown-container {\r\n margin-left: 8px;\r\n min-width: 300px;\r\n }\r\n\r\n @media (min-width: ${gridBreakPoints.sm}) {\r\n }\r\n\r\n @media (min-width: ${gridBreakPoints.lg}) {\r\n width: 1000px;\r\n\r\n .dropdown-container {\r\n margin-left: 14px;\r\n max-width: 300px;\r\n }\r\n }\r\n @media (min-width: ${gridBreakPoints.xl}) {\r\n width: 1100px;\r\n }\r\n\r\n label {\r\n margin-bottom: 6px;\r\n }\r\n }\r\n\r\n .payment-dropdown {\r\n display: flex;\r\n flex-direction: column;\r\n transform: translateY(24px);\r\n }\r\n\r\n > .row {\r\n padding-bottom: 10px;\r\n\r\n .left-field,\r\n .right-field {\r\n padding: 0;\r\n }\r\n }\r\n\r\n .price-span {\r\n float: right;\r\n transform: translateY(-4px);\r\n }\r\n .price-total {\r\n font-weight: bold;\r\n font-size: 16px;\r\n }\r\n\r\n .row-parent + .row-parent {\r\n margin-top: 4rem;\r\n }\r\n .row-child + .row-parent {\r\n margin-top: 1rem;\r\n }\r\n .row-child {\r\n margin-top: 1rem;\r\n padding-left: 1.5rem;\r\n }\r\n .btn-row {\r\n display: block;\r\n text-align: end;\r\n margin-top: 20px;\r\n margin-bottom: 15px;\r\n }\r\n .row-form-group {\r\n flex-direction: column;\r\n }\r\n .acknowledgements_cb > label > div > a,\r\n #termsLink {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkColor};\r\n :hover {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n .btn-link {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n :hover {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n .custom-control-input:checked ~ .custom-control-label::before {\r\n border-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n background-color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n .custom-control-label::after {\r\n border: #adb5bd solid 1px;\r\n }\r\n`\r\n\r\nexport const StyledLabelRequired = styled.span`\r\n display: flex;\r\n ::after {\r\n content: '*';\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n`\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledSignatureBox = styled.div`\r\n .canvas-wrapper {\r\n max-width: 420px;\r\n min-height: 105px;\r\n display: flex;\r\n flex-direction: column;\r\n background-color: #eeeeee;\r\n padding: 2rem 2rem 2rem 2rem;\r\n gap: 1rem;\r\n }\r\n .x-coord {\r\n position: relative;\r\n line-height: 4rem;\r\n\r\n .input-group-addon {\r\n transform: translateY(70px) translateX(-10px);\r\n }\r\n }\r\n .tool-bar {\r\n max-width: 420px;\r\n margin-bottom: 5px;\r\n width: inherit;\r\n display: flex;\r\n justify-content: space-between;\r\n\r\n .title {\r\n white-space: nowrap;\r\n font-weight: 600;\r\n font-size: 16px;\r\n }\r\n\r\n .clear-button {\r\n color: ${({ theme }) => theme.colors.InfinitiLinkColor};\r\n &:hover {\r\n cursor: pointer;\r\n text-decoration: underline;\r\n color: ${({ theme }) => theme.colors.InfinitiLinkHoverColor};\r\n }\r\n }\r\n }\r\n\r\n canvas {\r\n display: block;\r\n border: 1px solid;\r\n width: 90%;\r\n min-height: 105px;\r\n background-color: #fff;\r\n //border-radius: 8px 8px 0 0;\r\n }\r\n\r\n .signature-canvas {\r\n cursor: crosshair;\r\n }\r\n\r\n .signature-canvas.disabled {\r\n cursor: not-allowed;\r\n }\r\n\r\n .error-label {\r\n margin-top: -5px;\r\n margin-bottom: 5px;\r\n }\r\n .signature-content {\r\n display: inline-flex;\r\n justify-content: center;\r\n }\r\n`\r\n","import { useEffect, useRef, useState } from 'react'\r\n// import { IGetGroundingDetailsResponse } from 'types/groundingTypes'\r\nimport { StyledSignatureBox } from './SignatureBox.styled'\r\nimport SignatureCanvas from 'react-signature-canvas'\r\nimport { GroundingReturn } from '../../types/Grounding/GroundingResult'\r\nimport { GENERAL_ERROR_MESSAGE } from 'common/constants'\r\nimport { DispositionOption } from 'types/Grounding/groundingTypes'\r\n// import { ERROR_LESSEE_SIGNATURE_REQUIRED_MESSAGE, ERROR_RETAILER_SIGNATURE_REQUIRED_MESSAGE } from 'common/constants'\r\n// import { SignatureTypes } from 'types/groundingTypes'\r\n\r\ninterface ISignatureBoxProps {\r\n title: string\r\n canvasHeight: number\r\n index: number\r\n configText?: string\r\n groundingData: GroundingReturn\r\n image?: string\r\n setGroundingData?: (data: GroundingReturn) => void\r\n isSubmit: boolean\r\n isDisabled?: boolean\r\n signatureTypeId: number\r\n}\r\n\r\nexport const SignatureBox = ({\r\n title,\r\n canvasHeight,\r\n index,\r\n configText,\r\n groundingData,\r\n image,\r\n setGroundingData,\r\n isSubmit,\r\n isDisabled,\r\n signatureTypeId\r\n}: ISignatureBoxProps) => {\r\n let signatureTypes = [...groundingData?.signatureTypes]\r\n let signPad = useRef(null)\r\n const [isSign, setIsSign] = useState(false)\r\n\r\n const clear = () => {\r\n signPad.current.clear()\r\n setIsSign(false)\r\n updateSign('')\r\n }\r\n\r\n const updateSign = (url: string) => {\r\n signatureTypes[index].signatureImage = url\r\n let newData = { ...groundingData, signatureTypes: signatureTypes }\r\n setGroundingData(newData)\r\n }\r\n\r\n const drawLineToCanvas = (canvas: HTMLCanvasElement) => {\r\n let canvasContext = canvas.getContext('2d')\r\n canvasContext.clearRect(0, 0, canvas.width, canvas.height)\r\n canvasContext.fillStyle = 'white'\r\n canvasContext.fillRect(0, 0, canvas.width, canvas.height)\r\n canvasContext.beginPath()\r\n canvasContext.lineWidth = 2\r\n canvasContext.strokeStyle = '#ccc'\r\n canvasContext.moveTo(5, 85)\r\n canvasContext.lineTo(canvas.width - 5, 85)\r\n canvasContext.stroke()\r\n canvasContext.closePath()\r\n\r\n canvasContext.lineWidth = 2\r\n canvasContext.strokeStyle = '#145394'\r\n }\r\n\r\n const drawLineToCanvasByIndex = (index: number | null = null) => {\r\n const signCanvases = document.querySelectorAll('.signature-canvas')\r\n if (index !== null) {\r\n const canvas = signCanvases && (signCanvases[index] as HTMLCanvasElement)\r\n if (canvas) {\r\n drawLineToCanvas(canvas)\r\n }\r\n } else {\r\n signCanvases?.forEach((canvas: HTMLCanvasElement, i: number) => {\r\n drawLineToCanvas(canvas)\r\n })\r\n }\r\n }\r\n\r\n const init = () => {\r\n const canvas = document.getElementById(`signature-${title.toLowerCase()}`)\r\n canvas.addEventListener(\r\n 'mouseleave',\r\n function (e: MouseEvent) {\r\n if (!signPad.current.isEmpty()) {\r\n setIsSign(true)\r\n updateSign(signPad.current.toDataURL())\r\n }\r\n },\r\n false\r\n )\r\n canvas.addEventListener(\r\n 'touchend',\r\n function (e: MouseEvent) {\r\n if (!signPad.current.isEmpty()) {\r\n setIsSign(true)\r\n updateSign(signPad.current.toDataURL())\r\n }\r\n },\r\n false\r\n )\r\n }\r\n\r\n useEffect(() => {\r\n drawLineToCanvasByIndex()\r\n init()\r\n // updateSign('')\r\n if (image !== '') {\r\n signPad.current.fromDataURL(image)\r\n setIsSign(true)\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (signPad.current) {\r\n if (isDisabled) {\r\n signPad.current.off()\r\n }\r\n }\r\n }, [isDisabled])\r\n\r\n return (\r\n \r\n \r\n
{title}
\r\n {!isDisabled && (\r\n
{\r\n clear()\r\n drawLineToCanvasByIndex(index)\r\n }}\r\n >\r\n Clear Signature\r\n \r\n )}\r\n
\r\n \r\n
\r\n {groundingData?.groundingDispositionSelected.ID !== DispositionOption.LESSEE_PURCHASE &&\r\n groundingData?.groundingDispositionSelected.ID !==\r\n DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT && (\r\n
\r\n {configText}\r\n
\r\n )}\r\n
\r\n \r\n
\r\n
\r\n
\r\n\r\n {isSubmit && !isSign && GENERAL_ERROR_MESSAGE}
\r\n \r\n )\r\n}\r\n","import { assetFolders } from 'common/constants'\r\nimport { Modal } from 'react-bootstrap'\r\nimport styled from 'styled-components'\r\n\r\nexport const StyledConfirmModal = styled(Modal)`\r\n min-width: 700px;\r\n\r\n .modal-content {\r\n width: fit-content;\r\n }\r\n\r\n .modal-body {\r\n width: 512px;\r\n padding: 1rem 1.5rem;\r\n }\r\n\r\n .modal-title {\r\n font-size: 13px;\r\n text-transform: uppercase;\r\n text-shadow: 0 0 1px rgba(0, 0, 0, 0.6);\r\n }\r\n\r\n .modal-header {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 0.5rem 1.5rem 0;\r\n border-bottom: none;\r\n /* margin: 8px 0px; */\r\n }\r\n\r\n .modal-final-sale {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 42px;\r\n\r\n label {\r\n text-transform: uppercase;\r\n font-weight: bolder;\r\n color: #c3002f;\r\n }\r\n\r\n img {\r\n transform: scale(0.6) translateY(-6px) translateX(12px);\r\n }\r\n }\r\n\r\n .modal-btn-group {\r\n }\r\n`\r\n\r\nexport const StyledButtonContainer = styled.div<{ assetFolder?: string }>`\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 26px;\r\n /* margin-top: 1.5rem; */\r\n\r\n .btn-popup {\r\n border-radius: 2px;\r\n color: #fff;\r\n font-size: 11px;\r\n text-align: center;\r\n padding: 0.57143em 1.42857em 0.35714em;\r\n padding-top: 0.57143em;\r\n padding-bottom: 0.35714em;\r\n cursor: pointer;\r\n width: 390px;\r\n height: 46px;\r\n line-height: 12px;\r\n white-space: normal;\r\n word-wrap: break-word;\r\n text-transform: uppercase;\r\n border: none;\r\n }\r\n\r\n .btn-neglect {\r\n padding-left: 34px;\r\n padding-right: 49px;\r\n background-color: ${({ assetFolder }) => (assetFolder === assetFolders.Infiniti ? '#606060' : '#c3002f')};\r\n border: ${({ assetFolder }) => assetFolder === assetFolders.Infiniti && 'solid 1.5px black'};\r\n }\r\n\r\n .btn-neglect:hover {\r\n background-color: ${({ assetFolder }) => (assetFolder === assetFolders.Infiniti ? '#ccc' : '#a50129')};\r\n color: ${({ assetFolder }) => assetFolder === assetFolders.Infiniti && '#666'};\r\n }\r\n\r\n .btn-confirm {\r\n padding-left: 31px;\r\n padding-right: 13px;\r\n background-color: ${({ assetFolder }) => (assetFolder === assetFolders.Infiniti ? 'white' : '#508f40')};\r\n color: ${({ assetFolder }) => assetFolder === assetFolders.Infiniti && 'black'};\r\n border: ${({ assetFolder }) => assetFolder === assetFolders.Infiniti && 'solid 1.5px black'};\r\n }\r\n\r\n .btn-confirm:hover {\r\n background-color: ${({ assetFolder }) => (assetFolder === assetFolders.Infiniti ? '#000' : '#327322')};\r\n color: ${({ assetFolder }) => assetFolder === assetFolders.Infiniti && '#fff'};\r\n }\r\n`\r\n","import { Modal, Button } from 'react-bootstrap'\r\nimport { StyledButtonContainer, StyledConfirmModal } from './FinalAckModal.styled'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\n\r\ninterface IProps {\r\n show: boolean\r\n onClose: any\r\n events: {\r\n setShowModal: any\r\n handleAcknowledgedConfirm: any\r\n }\r\n}\r\n\r\nexport const FinalAckModal = ({ show, onClose, events }: IProps) => {\r\n const [assetFolder] = useGlobalStore((state) => [state.userClaims.CurrentBuyerTypeAssetFolder])\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n
\r\n

\r\n
\r\n
\r\n
\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n )\r\n}\r\nexport default FinalAckModal\r\n","import { Alert, Button, Col, Form, Row } from 'react-bootstrap'\r\nimport { StyledTurnIn, StyledTurnInTitle, StyledTurnIns } from './GroundingTurnIn.styled'\r\nimport { HTMLText } from 'components/Share/HtmlText'\r\nimport { SignatureBox } from '../../components/Grounding/SignatureBox'\r\nimport { DropDownData, DropDownGroup, GroundingConfigurationSignatureType } from '../../types/Grounding/GroundingResult'\r\nimport DividerWidthText from 'components/Grounding/DividerWidthText'\r\nimport GroundingVehicleDetails from 'components/Grounding/GroundingVehicleDetails'\r\nimport { useGroundingStore } from './store/useGroundingStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { useState, useEffect, useMemo } from 'react'\r\nimport { DispositionOption } from 'types/Grounding/groundingTypes'\r\nimport { DropdownList } from 'layouts/DropdownList'\r\nimport { StyledLabelRequired } from './GroundingTurnIn.styled'\r\nimport FinalAckModal from 'components/Grounding/FinalAckModal'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { saveGrounding } from 'apis/groundingApis'\r\nimport { GENERAL_ERROR_MESSAGE } from 'common/constants'\r\nimport { OverlayLoader } from 'components/Loader'\r\nimport { GroundingRenderStep } from './store/RenderStep'\r\nimport { useGroundingActionStore } from './store/useGroundingActionStore'\r\n\r\ninterface IProps {\r\n setShowCancelModal: (data: boolean) => void\r\n}\r\n\r\nexport const GroundingTurnIn = ({ setShowCancelModal }: IProps) => {\r\n const [groundingData, setGroundingData, defaultGroundingData, setShowTerms] = useGroundingStore(\r\n (state) => [state.groundingData, state.setGroundingData, state.defaultGroundingData, state.setShowTerms],\r\n shallow\r\n )\r\n const [activeStep, setActiveStep, setIsBack] = useGroundingActionStore(\r\n (state) => [state.activeStep, state.setActiveStep, state.setIsBack],\r\n shallow\r\n )\r\n\r\n const [getSystemSettings] = useGlobalStore((state) => [state.getSystemSetting])\r\n const receivingDealershipPhoneVisibility =\r\n Number(getSystemSettings('DISPLAY_RECEIVING_DEALERSHIP_PHONE_SECTION')) ?? 0\r\n const [attributes, setAttributes] = useState([])\r\n const [signatures, setSignatures] = useState(groundingData?.signatureTypes)\r\n const [paymentTypes, setPaymentTypes] = useState([])\r\n\r\n const [selectedNoSignReason, setSelectedNoSignReason] = useState(groundingData?.selectedNoSignReason)\r\n const [isSubmit, setIsSubmit] = useState(false)\r\n const [showFinalAckModal, setShowFinalAckModal] = useState(false)\r\n\r\n const [selectedAcknowledgements, setSelectedAcknowledgements] = useState([])\r\n const [selectedPaymentType, setSelectedPaymentType] = useState(groundingData?.selectedPayment)\r\n const [isLoading, setIsLoading] = useState(false)\r\n const [selectedNoSignReasonErrorMessage, setSelectedNoSignReasonErrorMessage] = useState('')\r\n const [showErrorMessage, setShowErrorMessage] = useState(false)\r\n\r\n const allowPaymentOption = useMemo(() => {\r\n return (\r\n (groundingData?.groundingDispositionSelected.ID === DispositionOption.DEALER_INVENTORY_PURCHASE ||\r\n groundingData?.groundingDispositionSelected.ID === DispositionOption.LESSEE_PURCHASE ||\r\n groundingData?.groundingDispositionSelected.ID ===\r\n DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT) &&\r\n groundingData?.purchasePriceString !== undefined &&\r\n groundingData?.performPurchase\r\n )\r\n }, [groundingData])\r\n\r\n useEffect(() => {\r\n if (groundingData?.paymentTypes.length > 0 && allowPaymentOption) {\r\n setSelectedPaymentType(groundingData?.paymentTypes[0]?.ID)\r\n }\r\n const link = document.getElementById('termsLink')\r\n if (link) {\r\n link.addEventListener('click', handleClick)\r\n }\r\n\r\n return () => {\r\n if (link) {\r\n link.removeEventListener('click', handleClick)\r\n }\r\n }\r\n }, [])\r\n\r\n const handleClick = (event) => {\r\n event.preventDefault() // Prevent default navigation\r\n setShowTerms(true)\r\n }\r\n\r\n useEffect(() => {\r\n const atts = groundingData?.attributes\r\n setAttributes(atts)\r\n\r\n setPaymentTypes(groundingData?.paymentTypes)\r\n\r\n groundingData?.signatureTypes.forEach((signatureType) => {\r\n if (signatureType.SignatureType.toLowerCase() === 'lessee') {\r\n if (signatureType.SelectedNoSignReason === 0) {\r\n setSelectedNoSignReasonErrorMessage(GENERAL_ERROR_MESSAGE)\r\n } else {\r\n setSelectedNoSignReasonErrorMessage('')\r\n }\r\n }\r\n })\r\n }, [groundingData, selectedNoSignReason])\r\n\r\n const FormatPhoneNumber = function (phone: string) {\r\n var numbers = phone.replace(/\\D/g, ''),\r\n char = { 0: '(', 3: ') ', 6: '-' }\r\n phone = ''\r\n for (var i = 0; i < numbers.length; i++) {\r\n phone += (char[i] || '') + numbers[i]\r\n }\r\n return phone\r\n }\r\n\r\n const handleCheckboxChange = (event: React.ChangeEvent) => {\r\n const { checked, value } = event.target\r\n setSelectedAcknowledgements((prevSelectedAcknowledgements) => {\r\n if (checked) {\r\n return [...prevSelectedAcknowledgements, Number(value)]\r\n } else {\r\n return prevSelectedAcknowledgements.filter((acknowledgement) => acknowledgement !== Number(value))\r\n }\r\n })\r\n }\r\n\r\n const handleNoSignReasonChange = (id: number, signIndex: number) => {\r\n setSelectedNoSignReason(id)\r\n let signatureTypes = [...signatures]\r\n signatureTypes[signIndex].SelectedNoSignReason = id\r\n let newData = { ...groundingData }\r\n newData.signatureTypes = signatureTypes\r\n newData.selectedNoSignReason = id\r\n setGroundingData(newData)\r\n setSignatures((prevSignatures) => {\r\n return prevSignatures.map((signature) => {\r\n if (signature.ID === id) {\r\n return { ...signature, selectedNoSignReason: id }\r\n }\r\n return signature\r\n })\r\n })\r\n }\r\n\r\n const handlePaymentTypeChange = (id: number) => {\r\n setSelectedPaymentType(id)\r\n let newData = { ...groundingData, selectedPayment: id }\r\n setGroundingData(newData)\r\n }\r\n\r\n const checkNotSelectAllAcknowledgements = () => {\r\n if (\r\n (groundingData?.selectedDisposition === DispositionOption.LESSEE_PURCHASE ||\r\n groundingData?.selectedDisposition === DispositionOption.DEALER_INVENTORY_PURCHASE_WITH_NEW_NMAC_CONTRACT) &&\r\n selectedAcknowledgements.length !==\r\n groundingData?.acknowledgements.filter((x) =>\r\n x.DispositionTypeID.split(',').find((x) => x === groundingData?.selectedDisposition.toString())\r\n ).length\r\n ) {\r\n return true\r\n }\r\n return false\r\n }\r\n\r\n const handleValidationBeforeSubmit = () => {\r\n setIsSubmit(true)\r\n let isReadySubmit = true\r\n\r\n signatures.forEach((signatureType) => {\r\n if (signatureType.signatureImage === null || signatureType.signatureImage === '') {\r\n isReadySubmit = false\r\n }\r\n\r\n if (signatureType.SignatureType.toLowerCase() === 'lessee') {\r\n if (\r\n signatureType.SelectedNoSignReason === 0 ||\r\n (signatureType.SelectedNoSignReason !== 0 &&\r\n signatureType.NoSignReasons?.filter(\r\n (e) => e.DispositionTypeID === groundingData?.groundingDispositionSelected.ID\r\n ).find((x) => x.ID === signatureType.SelectedNoSignReason) === undefined)\r\n ) {\r\n setSelectedNoSignReasonErrorMessage(GENERAL_ERROR_MESSAGE)\r\n isReadySubmit = false\r\n } else {\r\n setSelectedNoSignReasonErrorMessage('')\r\n }\r\n }\r\n })\r\n\r\n if (\r\n checkNotSelectAllAcknowledgements() ||\r\n (allowPaymentOption && groundingData?.paymentTypes.length > 0 && groundingData?.selectedPayment === undefined)\r\n ) {\r\n isReadySubmit = false\r\n }\r\n\r\n if (isReadySubmit === false) {\r\n setShowErrorMessage(true)\r\n window.scrollTo(0, 0)\r\n return false\r\n }\r\n\r\n return true\r\n }\r\n\r\n const handleFinalSubmit = async () => {\r\n setShowFinalAckModal(false)\r\n updateGroundingData()\r\n\r\n try {\r\n setIsLoading(true)\r\n\r\n let newGroundingData = JSON.parse(JSON.stringify(groundingData))\r\n\r\n const result = await saveGrounding(groundingData)\r\n if ((result?.ErrorMessage !== '' && result?.ErrorMessage !== undefined) || result?.SavePayoffError) {\r\n newGroundingData.ErrorMessage = result?.ErrorMessage ?? result?.SavePayoffError\r\n if (result?.viewGroundingQuickStart == null) newGroundingData.viewGroundingQuickStart = false\r\n else newGroundingData.viewGroundingQuickStart = result?.viewGroundingQuickStart\r\n }\r\n newGroundingData.VehicleDocuments = result?.VehicleDocuments\r\n if (result?.AllowOffer !== undefined) newGroundingData.AllowOffer = result?.AllowOffer\r\n if (result?.purchasePriceString === '$0') newGroundingData.purchasePriceString = '$0'\r\n setGroundingData(newGroundingData)\r\n\r\n setActiveStep(GroundingRenderStep.GRD_RESULT)\r\n } catch (error) {\r\n console.log(error)\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n const updateGroundingData = () => {\r\n if (groundingData) {\r\n let newGroundingData = JSON.parse(JSON.stringify(groundingData))\r\n newGroundingData.selectedPayment = selectedPaymentType\r\n setGroundingData(newGroundingData)\r\n }\r\n }\r\n\r\n const handleDeclineFinalAck = () => {\r\n defaultGroundingData.purchasePrice = 0\r\n defaultGroundingData.purchasePriceString = '$0'\r\n defaultGroundingData.buyerFee = 0\r\n defaultGroundingData.buyerFeeString = ''\r\n defaultGroundingData.encryptedPurchasePrice = ''\r\n window.scrollTo(0, 0)\r\n setGroundingData(defaultGroundingData)\r\n //handleDeclineFinalAcknowledgement()\r\n if (activeStep !== GroundingRenderStep.GRD_TURN_IN) {\r\n return\r\n }\r\n setIsBack(false)\r\n setActiveStep(GroundingRenderStep.GRD_OPTIONS)\r\n }\r\n\r\n return (\r\n \r\n {isLoading && }\r\n \r\n \r\n Grounding Completion Date: {groundingData?.groundingDate}
\r\n \r\n \r\n {showErrorMessage && (\r\n setShowErrorMessage(false)}\r\n dismissible\r\n >\r\n {'Please review errors and resubmit'}\r\n \r\n )}\r\n \r\n
\r\n \r\n \r\n \r\n \r\n Date Grounded: \r\n {groundingData?.groundingDate}\r\n \r\n \r\n \r\n \r\n Date Turned In: \r\n {new Date(groundingData?.vehicleReturnDate).toLocaleDateString()}\r\n \r\n \r\n \r\n \r\n Odometer Reading: \r\n {groundingData?.odometerReading}\r\n \r\n \r\n {attributes?.map((e) => (\r\n \r\n \r\n {e.Description}: \r\n {e.selectedID?.FieldDescription}\r\n \r\n \r\n ))}\r\n
\r\n \r\n \r\n \r\n Dealership Name: \r\n {groundingData?.lessorName}\r\n \r\n \r\n \r\n \r\n Dealership Address: \r\n {groundingData?.initLocations?.map((x) => (\r\n <>\r\n {x.ID === groundingData?.selectedAddress && (\r\n <>\r\n {[x?.Address1, x?.Address2, x?.City, x?.StateCode]\r\n .filter((value) => value !== '' && value !== undefined)\r\n .join(', ') +\r\n ' ' +\r\n x?.Zip}\r\n >\r\n )}\r\n >\r\n ))}\r\n \r\n \r\n {receivingDealershipPhoneVisibility === 1 && (\r\n \r\n \r\n Dealership Phone: \r\n {FormatPhoneNumber(groundingData?.buyerPhoneNo)}\r\n \r\n \r\n )}\r\n
\r\n\r\n \r\n \r\n {\r\n handleDeclineFinalAck()\r\n setShowFinalAckModal(false)\r\n }}\r\n events={{\r\n handleAcknowledgedConfirm: handleFinalSubmit,\r\n setShowModal: setShowFinalAckModal\r\n }}\r\n >\r\n \r\n \r\n )\r\n}\r\n\r\nexport default GroundingTurnIn\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledGroundingWithVIN = styled.div`\r\n .spinner-row {\r\n display: flex;\r\n align-content: center;\r\n justify-content: center;\r\n }\r\n .form-control:focus {\r\n border-color: ${({ theme }) => {\r\n return theme.carousel.buttonBorder\r\n }}!important;\r\n outline: 0;\r\n box-shadow: ${({ theme }) => {\r\n return '0 0 0 0' + theme.carousel.buttonBorder\r\n }}!important;\r\n }\r\n`\r\n","import { checkGroundingService, getGroundingConfigurationByVIN } from 'apis/groundingApis'\r\nimport { CustomLoader } from 'components/Loader'\r\nimport { Formik } from 'formik'\r\nimport { useEffect, useState } from 'react'\r\nimport { Alert, Button, Col, Form, Row } from 'react-bootstrap'\r\nimport * as Yup from 'yup'\r\nimport shallow from 'zustand/shallow'\r\nimport { GroundingRenderStep } from './store/RenderStep'\r\nimport { useGroundingStore } from './store/useGroundingStore'\r\nimport { IVinSearchForm, initialVinValues } from 'types/Grounding/groundingTypes'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { SessionStorageKey, VIN_CHARACTERS_REGEX } from 'common/constants'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { StyledGroundingWithVIN } from './GroundingWithVIN.styled'\r\nimport { useGroundingActionStore } from './store/useGroundingActionStore'\r\n\r\nconst schema = Yup.object({\r\n VIN: Yup.string().length(17, 'Must be 17 characters').required('Required')\r\n})\r\n\r\nexport interface IProps {\r\n setLocationSelected?: (locationID: number) => void\r\n handleSetDefaultGroundingData?: (data) => void\r\n}\r\n\r\nexport const GroundingWithVIN = () => {\r\n const { getFeatureToggle } = useGlobalStore()\r\n const showGroundingPageLoadingBar = getFeatureToggle('GroundingPageLoadingBar') as string\r\n const [setGroundingData, setDefaultGroundingData, setAlreadyConfirmRecall, setAlreadyConfirmGeneralModal] =\r\n useGroundingStore(\r\n (state) => [\r\n state.setGroundingData,\r\n state.setDefaultGroundingData,\r\n state.setAlreadyConfirmRecall,\r\n state.setAlreadyConfirmGeneralModal\r\n ],\r\n shallow\r\n )\r\n\r\n const [setActiveStep] = useGroundingActionStore((state) => [state.setActiveStep], shallow)\r\n\r\n const [showMessage, setShowMessage] = useState(false)\r\n const [isLoading, setIsLoading] = useState(false)\r\n const [errorMessage, setErrorMessage] = useState('')\r\n const [hasAlreadyChanged, setHasAlreadyChanged] = useState(false)\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n\r\n const history = useHistory()\r\n\r\n const handleSearchGrounding = (values: IVinSearchForm) => {\r\n if (values?.VIN) {\r\n getInitialGroundingData(values?.VIN)\r\n }\r\n }\r\n\r\n useEffect(() => {\r\n setAlreadyConfirmRecall(false)\r\n setAlreadyConfirmGeneralModal(false)\r\n setGroundingData(null)\r\n let isServiceRunning = checkGroundingService()\r\n if (!isServiceRunning) {\r\n setErrorMessage(\r\n 'We are currently experiencing technical difficulties with the grounding process. Please try back again in a few minutes. We apologize for the inconvenience.'\r\n )\r\n setShowMessage(true)\r\n return\r\n }\r\n let VIN = sessionStorage.getItem(SessionStorageKey.GROUND_VIN)\r\n if (VIN !== null && VIN !== '') {\r\n sessionStorage.setItem(SessionStorageKey.GROUND_VIN, '')\r\n initialVinValues.VIN = VIN\r\n setHasAlreadyChanged(true)\r\n getInitialGroundingData(VIN)\r\n }\r\n }, [])\r\n\r\n const getInitialGroundingData = async (VIN: string) => {\r\n try {\r\n setIsLoading(true)\r\n const response = await getGroundingConfigurationByVIN(VIN)\r\n\r\n if (response) {\r\n if ((response.ErrorMessage !== undefined && response.ErrorMessage !== '') || response.SavePayoffError) {\r\n setErrorMessage(response.ErrorMessage ?? response.SavePayoffError)\r\n setShowMessage(true)\r\n return\r\n }\r\n response.GroundingNotice = response.GroundingNotice?.replace(\r\n 'Terms and Conditions',\r\n 'Terms and Conditions'\r\n )\r\n response.vehicleReturnDate = null\r\n initialVinValues.VIN = VIN\r\n setGroundingData(response)\r\n setDefaultGroundingData(response)\r\n setActiveStep(GroundingRenderStep.GRD_OPTIONS)\r\n }\r\n } catch (error) {\r\n console.log(error)\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n handleSearchGrounding(values)}\r\n validationSchema={schema}\r\n onReset={() => {\r\n setShowMessage(false)\r\n initialVinValues.VIN = ''\r\n }}\r\n >\r\n {(props) => (\r\n \r\n )}\r\n \r\n \r\n
\r\n {Number(showGroundingPageLoadingBar) === 1 && isLoading && (\r\n {}
\r\n )}\r\n {!isLoading && (\r\n \r\n \r\n {showMessage && (\r\n setShowMessage(false)} dismissible>\r\n {getLocalText(errorMessage, errorMessage)}\r\n \r\n )}\r\n \r\n
\r\n )}\r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const GroundingContainer = styled.div`\r\n margin: 3rem 4rem;\r\n`\r\nexport const StyledHeaderContainer = styled.div`\r\n h3 {\r\n color: ${({ theme }) => theme.colors.InfinitiOnlyColor};\r\n }\r\n\r\n margin-bottom: 3rem;\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n`\r\n","import React from 'react'\r\nimport GroundingConfirmModal from './GroundingConfirmModal'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\n\r\ninterface IProps {\r\n show: boolean\r\n setShowTerms: (data: boolean) => void\r\n}\r\n\r\nconst TermsModal = ({ show, setShowTerms }: IProps) => {\r\n const [getLocalText] = useGlobalStore((state) => [state.getLocalText])\r\n const termsLink = getLocalText('termsLink', 'termsLink')\r\n const termsText = getLocalText('termsText', 'termsText')\r\n\r\n function unescapeHTML(htmlString) {\r\n var doc = new DOMParser().parseFromString(htmlString, 'text/html')\r\n return doc.documentElement.textContent\r\n }\r\n\r\n return (\r\n setShowTerms(false)\r\n }}\r\n />\r\n )\r\n}\r\n\r\nexport default TermsModal\r\n","import { Layout } from 'layouts/Layout'\r\nimport { GroundingStepper } from 'modules/Grounding/GroundingStepper'\r\nimport GroundingOptions from 'modules/Grounding/GroundingOptions'\r\nimport GroundingResult from 'modules/Grounding/GroundingResult'\r\nimport GroundingTurnIn from 'modules/Grounding/GroundingTurnIn'\r\nimport { GroundingWithVIN } from 'modules/Grounding/GroundingWithVIN'\r\nimport { GroundingRenderStep } from 'modules/Grounding/store/RenderStep'\r\nimport { useGroundingStore } from 'modules/Grounding/store/useGroundingStore'\r\nimport shallow from 'zustand/shallow'\r\nimport { GroundingContainer, StyledHeaderContainer } from './Grounding.styled'\r\nimport { useEffect, useState } from 'react'\r\nimport TermsModal from 'components/Grounding/TermsModal'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { Return_To_Dashboard } from 'common/constants'\r\nimport GroundingConfirmModal from 'components/Grounding/GroundingConfirmModal'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { GroundingStep, useGroundingActionStore } from 'modules/Grounding/store/useGroundingActionStore'\r\n\r\nexport const Grounding = () => {\r\n const [showTerms, setShowTerms] = useGroundingStore(\r\n (state) => [\r\n state.showTerms,\r\n state.setShowTerms,\r\n state.setAlreadyConfirmRecall,\r\n state.setAlreadyConfirmGeneralModal\r\n ],\r\n shallow\r\n )\r\n const [activeStep, setActiveStep, setGroundingStepInfor, isBack, setIsBack, setIsSubmit] = useGroundingActionStore(\r\n (state) => [\r\n state.activeStep,\r\n state.setActiveStep,\r\n state.setGroundingStepInfor,\r\n state.isBack,\r\n state.setIsBack,\r\n state.setIsSubmit\r\n ],\r\n shallow\r\n )\r\n\r\n const [showGroundingCancelModal, setShowGroundingCancelModal] = useState(false)\r\n const [showBackToEnterVinModal, setShowBackToEnterVinModal] = useState(false)\r\n\r\n const { getLocalText } = useGlobalStore((state) => state)\r\n const history = useHistory()\r\n const returnToDashboardText = getLocalText(\r\n Return_To_Dashboard,\r\n 'Are you sure you want to navigate away from this page? By leaving this window you will lose any changes you have made. Press OK to continue, or cancel to stay on the current page.'\r\n )\r\n const StepInit = [\r\n {\r\n label: 'ENTER VIN',\r\n stepIndex: GroundingRenderStep.GRD_ENTER_VIN,\r\n active: true,\r\n completed: false,\r\n disabled: false\r\n },\r\n {\r\n label: 'GROUNDING OPTIONS',\r\n stepIndex: GroundingRenderStep.GRD_OPTIONS,\r\n active: false,\r\n completed: false,\r\n disabled: true\r\n },\r\n {\r\n label: 'TURN IN',\r\n stepIndex: GroundingRenderStep.GRD_TURN_IN,\r\n active: false,\r\n completed: false,\r\n disabled: true\r\n },\r\n {\r\n label: 'RESULT',\r\n stepIndex: GroundingRenderStep.GRD_RESULT,\r\n active: false,\r\n completed: false,\r\n disabled: true\r\n }\r\n ] as GroundingStep[]\r\n\r\n useEffect(() => {\r\n setGroundingStepInfor(StepInit)\r\n }, [])\r\n\r\n useEffect(() => {\r\n let steps = [...StepInit]\r\n switch (activeStep) {\r\n case GroundingRenderStep.GRD_ENTER_VIN:\r\n setIsBack(false)\r\n break\r\n case GroundingRenderStep.GRD_OPTIONS:\r\n steps[GroundingRenderStep.GRD_ENTER_VIN].active = false\r\n steps[GroundingRenderStep.GRD_ENTER_VIN].completed = true\r\n steps[GroundingRenderStep.GRD_ENTER_VIN].disabled = false\r\n steps[activeStep].active = true\r\n steps[activeStep].disabled = false\r\n steps[activeStep].completed = false\r\n if (isBack) {\r\n steps[GroundingRenderStep.GRD_TURN_IN].completed = true\r\n steps[GroundingRenderStep.GRD_TURN_IN].disabled = false\r\n }\r\n break\r\n case GroundingRenderStep.GRD_TURN_IN:\r\n for (let i = 0; i < activeStep; i++) {\r\n steps[i].active = false\r\n steps[i].completed = true\r\n steps[i].disabled = false\r\n }\r\n steps[activeStep].active = true\r\n steps[activeStep].disabled = false\r\n steps[activeStep].completed = false\r\n break\r\n case GroundingRenderStep.GRD_RESULT:\r\n for (let i = 0; i < activeStep; i++) {\r\n steps[i].active = false\r\n steps[i].completed = true\r\n steps[i].disabled = true\r\n }\r\n steps[activeStep].active = true\r\n steps[activeStep].disabled = false\r\n steps[activeStep].completed = false\r\n break\r\n default:\r\n break\r\n }\r\n setGroundingStepInfor(steps)\r\n }, [activeStep])\r\n\r\n const handelStepperOnClick = (stepIndex: number) => {\r\n if (\r\n stepIndex === GroundingRenderStep.GRD_ENTER_VIN &&\r\n activeStep !== GroundingRenderStep.GRD_RESULT &&\r\n activeStep !== GroundingRenderStep.GRD_ENTER_VIN\r\n ) {\r\n setShowBackToEnterVinModal(true)\r\n } else {\r\n if (stepIndex == GroundingRenderStep.GRD_TURN_IN) {\r\n setIsSubmit(true)\r\n return\r\n }\r\n\r\n stepIndex < activeStep ? setIsBack(true) : setIsBack(false)\r\n setIsSubmit(false)\r\n setActiveStep(stepIndex)\r\n }\r\n }\r\n\r\n const handleAcknowledgedConfirm = () => {\r\n setShowBackToEnterVinModal(false)\r\n setActiveStep(GroundingRenderStep.GRD_ENTER_VIN)\r\n }\r\n\r\n return (\r\n \r\n \r\n \r\n GROUND A VEHICLE
\r\n {\r\n handelStepperOnClick(stepIndex)\r\n }}\r\n />\r\n \r\n \r\n {activeStep === GroundingRenderStep.GRD_ENTER_VIN && }\r\n {activeStep === GroundingRenderStep.GRD_OPTIONS && (\r\n \r\n )}\r\n {activeStep === GroundingRenderStep.GRD_TURN_IN && (\r\n \r\n )}\r\n {activeStep === GroundingRenderStep.GRD_RESULT && }\r\n
\r\n {showTerms && }\r\n \r\n {showGroundingCancelModal && (\r\n {\r\n setShowGroundingCancelModal(false)\r\n },\r\n setShowModal: setShowGroundingCancelModal,\r\n handleAcknowledgedConfirm: () => {\r\n setShowGroundingCancelModal(false)\r\n history.push('/')\r\n },\r\n handleClickXButton: () => {\r\n setShowGroundingCancelModal(false)\r\n }\r\n }}\r\n isShowHeader={false}\r\n isShowButton={true}\r\n isShowYesButton={false}\r\n isShowNoButton={false}\r\n isBackdropStatic={false}\r\n >\r\n )}\r\n {showBackToEnterVinModal && (\r\n {\r\n setShowBackToEnterVinModal(false)\r\n },\r\n setShowModal: setShowBackToEnterVinModal,\r\n handleAcknowledgedConfirm: handleAcknowledgedConfirm,\r\n handleClickXButton: () => {\r\n setShowBackToEnterVinModal(false)\r\n }\r\n }}\r\n isShowHeader={false}\r\n isShowButton={true}\r\n isShowYesButton={false}\r\n isShowNoButton={false}\r\n isBackdropStatic={false}\r\n >\r\n )}\r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\n\r\nexport const StyledAccordionTitle = styled.div``\r\nexport const StyledAccordionContent = styled.div`\r\n padding: 1rem;\r\n`\r\n\r\nexport const StyledAccordion = styled.div`\r\n padding: 1rem;\r\n\r\n &.normal-title ${StyledAccordionTitle} {\r\n text-transform: none;\r\n }\r\n ${StyledAccordionTitle} {\r\n text-transform: uppercase;\r\n font-size: 1.5rem;\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n`\r\n\r\nexport const StyledCustomAccordion = styled.div`\r\n border-bottom: 0.1rem solid #e5e5e5;\r\n &:hover {\r\n border-bottom: 0.25rem solid ${({ theme }) => theme.colors.primary};\r\n }\r\n`\r\n","import { faChevronDown, faChevronRight } from '@fortawesome/free-solid-svg-icons'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport classNames from 'classnames'\r\nimport { PropsWithChildren, useEffect, useState } from 'react'\r\n\r\nimport {\r\n StyledAccordion,\r\n StyledAccordionContent,\r\n StyledAccordionTitle,\r\n StyledCustomAccordion\r\n} from './CustomAccordion.styled'\r\nimport Collapse from 'components/Collapse'\r\n\r\ninterface IProps extends PropsWithChildren {\r\n defaultOpen?: boolean\r\n open?: boolean\r\n sectionTitle: React.ReactNode\r\n}\r\n\r\nexport const CustomAccordion = ({ defaultOpen, open, sectionTitle, className, children }: IProps) => {\r\n const [isOpen, setIsOpen] = useState(defaultOpen ?? false)\r\n useEffect(() => {\r\n setIsOpen(defaultOpen)\r\n }, [defaultOpen])\r\n\r\n useEffect(() => {\r\n setIsOpen((s) => open ?? s)\r\n }, [open])\r\n\r\n return (\r\n \r\n setIsOpen((open) => !open)} className={classNames(className)}>\r\n \r\n {sectionTitle}\r\n \r\n \r\n \r\n \r\n \r\n \r\n {children}\r\n \r\n \r\n )\r\n}\r\n","import { StyledAccordion, StyledAccordionTitle } from 'components/CustomAccordion/CustomAccordion.styled'\r\nimport { StyledRibbon } from 'components/Ribbon/Ribbon.styled'\r\nimport styled from 'styled-components'\r\nimport { CustomAccordion } from 'components/CustomAccordion/CustomAccordion'\r\n\r\nexport const StyledBuyerSearchHeader = styled.div``\r\nexport const StyledBuyerSearchAction = styled.div`\r\n padding-bottom: 2.5rem;\r\n border-bottom: 0.1rem solid #e5e5e5;\r\n`\r\nexport const StyledBuyerSearchContent = styled.div`\r\n height: 100%;\r\n\r\n .see-more {\r\n font-size: 1.6rem;\r\n font-weight: 600;\r\n color: ${({ theme }) => theme.colors.primary};\r\n }\r\n\r\n .selected-filter-label {\r\n text-transform: uppercase;\r\n color: #999;\r\n display: block;\r\n padding-bottom: 0.2rem;\r\n padding-left: 1rem;\r\n border-top: none;\r\n background-color: #f8f8f8;\r\n }\r\n\r\n ${StyledAccordion} {\r\n &.selected-filter {\r\n border-color: #fff;\r\n }\r\n }\r\n`\r\nexport const StyledMultiSelectFilterSection = styled.div<{ noOfCols?: number }>`\r\n display: flex;\r\n grid-template-columns: repeat(${({ noOfCols }) => noOfCols ?? 3}, 1fr);\r\n gap: 1rem;\r\n max-width: 100%;\r\n flex-wrap: wrap;\r\n\r\n .custom-control-label {\r\n width: 100%;\r\n }\r\n`\r\nexport const StyledRibbonLabel = styled.div`\r\n display: flex;\r\n gap: 2rem;\r\n width: 100%;\r\n\r\n ${StyledRibbon} {\r\n flex-grow: 2;\r\n\r\n .ribbon {\r\n width: 100%;\r\n text-align: center;\r\n\r\n .ribbon-title {\r\n filter: brightness(0.75);\r\n }\r\n }\r\n }\r\n`\r\nexport const StyledSliderFilterSection = styled.div``\r\nexport const StyledCarfaxFilterItemContainer = styled.div`\r\n & + & {\r\n margin-top: 0.75rem;\r\n }\r\n`\r\nexport const StyledCarfaxFilterItemHeader = styled.div`\r\n text-transform: uppercase;\r\n\r\n color: #999;\r\n display: block;\r\n margin-bottom: 0.5rem;\r\n padding-bottom: 0.2rem;\r\n border-bottom: 1px solid #ccc;\r\n border-top: none;\r\n font-weight: bold;\r\n`\r\nexport const StyledCarfaxFilterItemContent = styled.div`\r\n margin-left: 5px;\r\n`\r\nexport const StyledCarfaxAccordion = styled(CustomAccordion)`\r\n background-color: rgb(253, 251, 225);\r\n ${StyledAccordionTitle} img {\r\n width: 10rem;\r\n }\r\n`\r\n\r\nexport const BUYER_SEARCH_OFFSET_HEIGHT = 10\r\n\r\nexport const StyledBuyerSearch = styled.div`\r\n position: sticky;\r\n top: ${BUYER_SEARCH_OFFSET_HEIGHT}px;\r\n`\r\n\r\nexport const StyledFilterSection = styled.div`\r\n max-height: calc(100vh - 28rem);\r\n overflow: auto;\r\n\r\n ::-webkit-scrollbar-thumb {\r\n background-color: ${({ theme }) => theme.colors.primary};\r\n }\r\n\r\n ::-webkit-scrollbar {\r\n width: 0.4rem;\r\n }\r\n`\r\n","import styled from 'styled-components'\r\nimport { Col, Button, Form } from 'react-bootstrap'\r\n\r\nexport const SaveClearAllFilterGroupAction = styled.div`\r\n display: flex;\r\n justify-content: center;\r\n\r\n .btn {\r\n font-size: 1.6rem;\r\n padding-right: 0;\r\n padding-left: 0;\r\n\r\n &:disabled {\r\n color: ${({ theme }) => theme.colors.headerFontColor};\r\n }\r\n }\r\n`\r\nexport const SaveCancelGroupAction = styled(Col)`\r\n display: flex;\r\n justify-content: center;\r\n\r\n .btn {\r\n font-size: 1.4rem;\r\n }\r\n`\r\n\r\nexport const SaveLink = styled(Button)`\r\n color: ${({ theme }) => theme.colors.primary};\r\n\r\n &:active,\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n }\r\n\r\n padding-right: 0.5rem;\r\n padding-left: 0;\r\n`\r\n\r\nexport const SaveSearchContainer = styled.div`\r\n background: #fff;\r\n padding: 1rem 0;\r\n\r\n .btn-link {\r\n color: ${({ theme }) => theme.colors.primary};\r\n\r\n &:active,\r\n &:hover {\r\n color: ${({ theme }) => theme.colors.linkColorLight};\r\n }\r\n }\r\n\r\n .form-check-input {\r\n margin-left: -2rem;\r\n }\r\n\r\n .btn {\r\n font-weight: 600;\r\n }\r\n\r\n .btn:is(:hover, :focus, :active) {\r\n box-shadow: none;\r\n text-decoration: none;\r\n }\r\n`\r\nexport const NotifyContainer = styled(Col)`\r\n display: flex;\r\n gap: 2rem;\r\n`\r\n\r\nexport const SaveSearchFormBody = styled(Form)<{ show: boolean }>`\r\n display: ${({ show }) => (show ? 'block' : 'none')};\r\n`\r\n\r\nexport const ActionSeparator = styled.span`\r\n font-weight: 600;\r\n font-size: 1.6rem;\r\n padding: 0.375rem 0.75rem;\r\n\r\n &::before {\r\n content: ' | ';\r\n }\r\n`\r\n","import {\r\n NotifyContainer,\r\n SaveSearchContainer,\r\n SaveClearAllFilterGroupAction,\r\n SaveCancelGroupAction,\r\n SaveLink,\r\n SaveSearchFormBody,\r\n ActionSeparator\r\n} from './SaveSearch.styled'\r\nimport { useEffect, useState } from 'react'\r\nimport { Button, Col, Form, Row } from 'react-bootstrap'\r\nimport { loadDayFiles, saveSearch } from 'apis/vehicleApis'\r\nimport { ISearchResponseData, SavedSearch, SavedSearchData } from 'types/vehicleTypes'\r\nimport { Formik } from 'formik'\r\nimport { useFetch } from 'hooks/useFetch'\r\nimport { Operation } from 'types/baseTypes'\r\nimport { TextDanger } from 'components/Forms'\r\nimport { DEFAULT_ERROR_MESSAGE, SessionStorageKey } from 'common/constants'\r\nimport { Rules } from 'common/rules'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { useDtmAnalytics } from 'hooks/useDtmAnalytics'\r\nimport { HTMLText } from 'components/Share/HtmlText'\r\nimport { parseHtml } from 'utils/stringUtils'\r\n\r\ninterface IProps {\r\n filtersData: ISearchResponseData[]\r\n onClearFilterClicked?: () => void\r\n onToggleSaveSearch?: (isOpen: boolean) => void\r\n}\r\n\r\nexport const SaveSearch = ({ filtersData, onClearFilterClicked, onToggleSaveSearch }: IProps) => {\r\n const [showSaveSearch, setShowSaveSearch] = useState(false)\r\n const [showErrorMsg, setShowErrorMsg] = useState(false)\r\n\r\n const { isInRule } = useGlobalStore()\r\n const canSaveSearch = isInRule(Rules.VIEW_SAVED_SEARCH_PAGE)\r\n const { userInteraction } = useDtmAnalytics()\r\n const getLocalText = useGlobalStore((state) => state.getLocalText)\r\n\r\n const { data: { search: currrentSearch, days, frequency, durations } = {} as SavedSearchData } = useFetch(() =>\r\n loadDayFiles()\r\n )\r\n\r\n const handleSaveSearch = async (searchData: SavedSearch) => {\r\n filtersData.forEach((item) => {\r\n if (item.DBFieldName === 'VIN' && item.Value !== '') {\r\n item.FriendlyValue = item.Value\r\n item.Selected = true\r\n item.ChildrenFilter = []\r\n item.Operator = Operation.Contains\r\n }\r\n })\r\n userInteraction(`BuyerSearch: SaveSearch`)\r\n try {\r\n await saveSearch({ filters: filtersData, searchData })\r\n setShowSaveSearch(false)\r\n } catch (error) {\r\n setShowErrorMsg(true)\r\n }\r\n }\r\n\r\n const descriptionChange = (event, props) => {\r\n props.setFieldValue('Description', event.target.value)\r\n }\r\n\r\n useEffect(() => {\r\n onToggleSaveSearch(showSaveSearch)\r\n }, [onToggleSaveSearch, showSaveSearch])\r\n\r\n return (\r\n \r\n \r\n {canSaveSearch && (\r\n <>\r\n \r\n \r\n >\r\n )}\r\n \r\n \r\n\r\n {canSaveSearch && (\r\n handleSaveSearch(values)}\r\n >\r\n {(props) => (\r\n \r\n \r\n descriptionChange(e, props)}\r\n value={props.values.Description}\r\n placeholder=\"Enter Save Search Title\"\r\n />\r\n \r\n \r\n \r\n \r\n Notify Me via Email?\r\n \r\n props.setFieldValue('NotifyMe', event.target.checked)}\r\n />\r\n \r\n \r\n props.setFieldValue('NotifyMe', !event.target.checked)}\r\n />\r\n \r\n \r\n
\r\n {props.values.NotifyMe && (\r\n <>\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n {frequency?.map((option) => {\r\n return (\r\n \r\n )\r\n })}\r\n \r\n \r\n {props.values.EmailRecurrance > 1 && (\r\n \r\n \r\n {days?.map((option) => {\r\n return (\r\n \r\n )\r\n })}\r\n \r\n \r\n )}\r\n\r\n \r\n \r\n {durations?.map((option) => {\r\n return (\r\n \r\n )\r\n })}\r\n \r\n \r\n
\r\n >\r\n )}\r\n\r\n \r\n \r\n \r\n Save\r\n \r\n \r\n \r\n
\r\n \r\n {showErrorMsg && {DEFAULT_ERROR_MESSAGE}}\r\n
\r\n \r\n )}\r\n \r\n )}\r\n \r\n )\r\n}\r\n","import styled from 'styled-components'\r\nimport ReactSlider from 'react-slider'\r\n\r\nexport const StyledThumb = styled.div`\r\n height: 2.4rem;\r\n width: 2.4rem;\r\n text-align: center;\r\n background-color: #fff;\r\n color: #000;\r\n border: 0.4rem solid ${({ theme }) => theme.colors.primary};\r\n\r\n // TODO: Find some ways to intervene this instead!!\r\n outline-color: ${({ theme }) => theme.colors.primary};\r\n outline-width: 0;\r\n\r\n border-radius: 50%;\r\n cursor: grab;\r\n\r\n .thumb-text {\r\n vertical-align: middle;\r\n margin-top: 2.5rem;\r\n display: flex;\r\n justify-content: center;\r\n }\r\n`\r\n\r\nexport const StyledTrack = styled.div<{ index: number; value: number[] }>`\r\n top: 1rem;\r\n height: 0.5rem;\r\n background: ${({ index, value, theme }) =>\r\n (value.length === 1 && index === 0) || (value.length === 2 && index === 1) ? theme.colors.primary : '#ddd'};\r\n border-radius: 999px;\r\n`\r\n\r\nexport const StyledMark = styled.span`\r\n padding: inherit;\r\n\r\n width: 1px;\r\n height: 10px;\r\n background-color: #ccc;\r\n cursor: pointer;\r\n vertical-align: middle;\r\n`\r\n\r\nexport const StyledSlider = styled(ReactSlider)`\r\n width: 100%;\r\n height: 5rem;\r\n\r\n ${StyledMark} {\r\n margin: 2rem 1.125rem;\r\n }\r\n`\r\n","import { StyledMark, StyledSlider, StyledThumb, StyledTrack } from './Slider.styled'\r\nimport { ReactSliderProps } from 'react-slider'\r\n\r\nconst renderThumb = (textRenderFn?: (value: number) => string) => (props, state) =>\r\n (\r\n \r\n {textRenderFn ? textRenderFn(state.valueNow) : state.valueNow}
\r\n \r\n )\r\nconst renderTrack = (props, state) => \r\nconst renderMark = (props) => \r\n\r\ninterface IProps extends ReactSliderProps {\r\n textRenderFn?: (value: number) => string\r\n}\r\n\r\nexport const Slider = ({ textRenderFn, ...props }: IProps) => {\r\n return (\r\n \r\n )\r\n}\r\n","import { BaseVehicleSearchCriteriaColumn as DBFieldId, PROXIMITY_FILTERS } from 'common/constants'\r\nimport Select from 'components/Select/Select'\r\nimport { Slider } from 'components/Slider/Slider'\r\nimport produce from 'immer'\r\nimport { isEmpty } from 'lodash'\r\nimport { useEffect, useState } from 'react'\r\nimport { Col, Form, Row } from 'react-bootstrap'\r\nimport { useGlobalStore } from 'store/useGlobalStore'\r\nimport { formatNumber } from 'utils/numberUtils'\r\nimport { formatDistanceLabel } from 'utils/utils'\r\n\r\nimport { ISearchFilterResult, ISearchResponseData } from '../../types/vehicleTypes'\r\nimport {\r\n StyledCarfaxFilterItemContainer,\r\n StyledCarfaxFilterItemContent,\r\n StyledCarfaxFilterItemHeader,\r\n StyledMultiSelectFilterSection,\r\n StyledSliderFilterSection\r\n} from './BuyerSearch.styled'\r\n\r\nconst ANY_DISTANCE_OPTION = '99999'\r\n\r\ninterface IProps {\r\n filter: ISearchResponseData | ISearchFilterResult\r\n onChange?: (filter: ISearchResponseData | ISearchFilterResult) => void\r\n}\r\n\r\nexport const SearchFilter = ({ filter, onChange }: IProps) => {\r\n const {\r\n userClaims: { CurrentBuyerPostCode }\r\n } = useGlobalStore()\r\n\r\n const [internalFilter, setInternalFilter] = useState(filter)\r\n const NO_FILTER_APPLICABLE = `No ${internalFilter.FieldName} filters applicable`\r\n\r\n useEffect(() => {\r\n setInternalFilter(filter)\r\n }, [filter])\r\n\r\n const onMultiSelectChange = (\r\n childPredicate: (filter: ISearchFilterResult) => boolean,\r\n isSelected: boolean,\r\n resetFirst?: boolean\r\n ) => {\r\n const result = produce(internalFilter, (draft) => {\r\n draft.ChildrenFilter.forEach((cf) => {\r\n if (resetFirst) cf.Selected = false\r\n if (childPredicate(cf)) cf.Selected = isSelected\r\n })\r\n })\r\n\r\n onChange?.(result)\r\n }\r\n\r\n const onMultiValueSliderChange = (minVal: number, maxVal: number, values: number[]) => {\r\n const result = produce(internalFilter, (draft) => {\r\n draft.Value = values[0].toString()\r\n draft.Value3 = values[1].toString()\r\n draft.Selected = true\r\n draft.FriendlyValue = `${values[0]} - ${values[1]}`\r\n\r\n if ((values[0] === 0 && values[1] === 0) || values[0] < minVal || values[1] > maxVal) {\r\n draft.Value = ''\r\n draft.Value3 = ''\r\n draft.Selected = false\r\n }\r\n })\r\n\r\n onChange?.(result)\r\n }\r\n\r\n const onProximityChange = (value: number) => {\r\n let selectedChild = null\r\n const result = produce(internalFilter, (ft) => {\r\n ft.ChildrenFilter.forEach((cf) => {\r\n if (cf.Selected) {\r\n selectedChild = cf\r\n }\r\n })\r\n\r\n ft.Value = value.toString()\r\n ft.FriendlyValue = formatDistanceLabel(ft.Value, ft?.Value2 ?? selectedChild?.Value2)\r\n ft.Selected = true\r\n })\r\n\r\n onChange?.(result)\r\n }\r\n\r\n const onZipCodeChange = (value: string) => {\r\n let selectedChild: ISearchFilterResult = null\r\n const result = produce(internalFilter, (ft) => {\r\n ft.ChildrenFilter.forEach((cf) => {\r\n if (cf.Selected) {\r\n cf.Value2 = value\r\n selectedChild = cf\r\n }\r\n })\r\n\r\n if (value !== CurrentBuyerPostCode) {\r\n if (ft.ChildrenFilter.find((item) => item.Selected) === undefined) ft.ChildrenFilter[0].Selected = true\r\n } else {\r\n ft.ChildrenFilter[0].Selected = false\r\n }\r\n\r\n ft.Value = ft.Value || selectedChild?.Value\r\n ft.Value2 = value\r\n ft.FriendlyValue = formatDistanceLabel(!ft.Value ? ANY_DISTANCE_OPTION : ft.Value, ft.Value2)\r\n ft.Selected = true\r\n })\r\n\r\n onChange?.(result)\r\n }\r\n\r\n const onConditionGradeChange = (minVal: number, maxVal: number, values: number[]) => {\r\n const result = produce(internalFilter, (draft) => {\r\n draft.Value = formatNumber(values[0], { minimumFractionDigits: 1 })\r\n draft.Value3 = formatNumber(values[1], { minimumFractionDigits: 1 })\r\n draft.Selected = true\r\n draft.FriendlyValue = `${draft.Value} - ${draft.Value3}`\r\n\r\n if ((values[0] === 0 && values[1] === 0) || values[0] < minVal || values[1] > maxVal) {\r\n draft.Value = ''\r\n draft.Value3 = ''\r\n draft.Selected = false\r\n }\r\n })\r\n\r\n onChange?.(result)\r\n }\r\n\r\n if (internalFilter.DBFieldName.startsWith('carfax')) {\r\n return (\r\n \r\n {internalFilter.FieldName}\r\n\r\n \r\n {isEmpty(internalFilter.ChildrenFilter) && <>{NO_FILTER_APPLICABLE}>}\r\n {!isEmpty(internalFilter.ChildrenFilter) && (\r\n \r\n {internalFilter.ChildrenFilter.map((cf, idx) => (\r\n \r\n {cf.FriendlyValue}{' '}\r\n ({cf.VehicleCount})\r\n \r\n }\r\n onChange={(e) => onMultiSelectChange((ft) => ft.FilterKey === cf.FilterKey, e.currentTarget.checked)}\r\n />\r\n ))}\r\n \r\n )}\r\n \r\n \r\n )\r\n }\r\n\r\n if (internalFilter.FieldId === DBFieldId.VIN) {\r\n const options = []\r\n const selectedOptions = []\r\n internalFilter.ChildrenFilter.forEach((cf) => {\r\n options.push({ value: cf.Value, label: cf.FriendlyValue })\r\n if (cf.Selected) selectedOptions.push({ value: cf.Value, label: cf.FriendlyValue })\r\n })\r\n\r\n return (\r\n