\n\nexport const useTransformToHtml = (text: string) => {\n return {__html: text};\n};\n","import { getDataServiceConfig } from 'src/feature-app';\n\nexport const useGetBrand = (): 'V' |'N' |undefined => {\n const data = getDataServiceConfig();\n const brand = data.customConfig?.brand;\n\n return brand;\n};\n","import { useGetBrand } from './use-get-brand';\n\nexport const useIsComerciales = () => {\n const brand = useGetBrand();\n\n return brand === 'N'; \n};\n","import { TrackingForm } from 'src/feature-app';\n\nexport interface NDPSField {\n name: string;\n value: string;\n}\n\nexport const getTrackingForm = (formResponse): TrackingForm => {\n let LeadID;\n if (formResponse && formResponse.content && formResponse.content.data && formResponse.content.data.fields) {\n const leadField: NDPSField = formResponse.content.data.fields.find(\n (field: NDPSField) => field.name === 'COD_LEAD_ID'\n );\n LeadID = leadField ? leadField.value : undefined;\n }\n return {\n LeadID,\n FormFields: undefined,\n };\n};\n","import { OneFormContent } from 'src/feature-app';\nimport { FormDataFields, FormDataFlags, FormDataHeaders } from 'src/types';\n\nexport const formDataBuilder = (data: any): FormData => {\n const formData = new FormData();\n\n for (const key in data) {\n if (data[key] === null || data[key] === 'null') {\n formData.append(key, '');\n } else {\n formData.append(key, data[key]);\n }\n }\n return formData;\n};\n\nexport const formatFormData = (object: object, string: string) => {\n if (typeof object !== 'object' || Object.keys(object).length === 0) {\n return {};\n }\n return Object.entries(object)\n .map((key) => [`${string}[${key[0]}]`, key[1]])\n .reduce((accum: FormDataFields, [k, v]) => {\n accum[k] = v;\n return accum;\n }, {});\n};\n\n/**\n * Formato de entrada: {DESC_FORM_VERSION: ''}\n * Formato de salida: {fields[DESC_FORM_VERSION]: ''}\n * @param fields\n */\nexport const formatFields = (fields: FormDataFields): FormDataFields => {\n return formatFormData(fields, 'fields');\n};\n\n/**\n * Formato de entrada: {DESC_FORM_DETAIL: ''}\n * Formato de salida: {headers[DESC_FORM_DETAIL]: ''}\n * @param headers\n */\nexport const formatHeaders = (headers: FormDataHeaders): FormDataHeaders => {\n return formatFormData(headers, 'headers');\n};\n\n/**\n * Formato de entrada: {DESC_FORM_DETAIL: ''}\n * Formato de salida: {flags[DESC_FORM_DETAIL]: ''}\n * @param flags\n */\nexport const formatFlags = (flags: FormDataFlags): FormDataFlags => {\n return formatFormData(flags, 'flags');\n};\n\nexport const getDpsFields = (faContent: OneFormContent) => {\n if (faContent && faContent.dpsFields && faContent.dpsFields.length > 0) {\n const headers = faContent.dpsFields.reduce((initialValue, header) => {\n const key = header.field;\n const value = header.value;\n const obj = { [key]: value };\n initialValue = { ...initialValue, ...obj };\n return initialValue;\n }, {});\n\n return { ...headers };\n }\n return null;\n};\n","export const TIME_FOR_TRANSFORM = 400;\nexport const TIME_FOR_TRANSFORM_MS = `${TIME_FOR_TRANSFORM}ms`;\n\nexport const TIME_FOR_OPACITY = 600;\nexport const TIME_FOR_OPACITY_MS = `${TIME_FOR_OPACITY}ms`;\n\nexport const TOKEN_LEADS_COMERCIALES = 'LCV_DDB_FRM_LEM_REC_LEM';\nexport const TOKEN_LEADS_TURISMOS = 'VW_DDB_FRM_LEM_REC_LEM';\n","import {\n Breakpoints,\n BreakpointWrapper,\n} from '@volkswagen-onehub/components-core';\nimport React from 'react';\n\nexport const CTAsSiNo = [\n { label: 'Sí', value: 'true' },\n { label: 'No', value: 'false' },\n];\n\nexport const contactoOptionsTurismos = [\n {\n value: 'Email',\n label: 'Email',\n },\n {\n value: 'Teléfono',\n label: 'Teléfono',\n },\n {\n value: 'Videollamada',\n label: 'Videollamada',\n },\n];\n\nexport const contactoOptionsComerciales = [\n {\n value: 'Teléfono',\n label: 'Teléfono',\n },\n {\n value: 'Email',\n label: 'Email',\n },\n];\nexport const CTAsHorario = [\n { label: 'Por la mañana', value: 'morning' },\n { label: 'Al mediodía', value: 'afternon' },\n { label: 'Por la tarde', value: 'evening' },\n];\n\n//Cita posventa\n\n export interface CTAsMotivoDef {\n label: string;\n value: string;\n detalles?: string | JSX.Element;\n detallesPrevStep?: string;\n}\n\nexport const CTAsMotivo: CTAsMotivoDef[] = [\n {\n label: 'Mantenimiento',\n value: 'MANTENIMIENTO',\n detalles: 'la revisión de mantenimiento',\n detallesPrevStep: 'Revisión de mantenimiento',\n },\n {\n label: 'Neumáticos',\n value: 'NEUMATICOS',\n detalles: 'el cambio de neumáticos',\n detallesPrevStep: 'Cambio de neumáticos',\n },\n { label: 'Avería', value: 'REPARACION', detalles: 'la avería', detallesPrevStep: 'Reparación de avería' },\n {\n label: 'Revisión pre-ITV',\n value: 'PREITV',\n detalles: (\n <>\n la revisión{' '}\n
\n \n \n pre-ITV\n >\n ),\n detallesPrevStep: 'Revisión pre-ITV',\n },\n {\n label: 'Chapa y pintura',\n value: 'CARROCERIA',\n detalles: 'la reparación de chapa y pintura',\n detallesPrevStep: 'Reparación de chapa y pintura',\n },\n {\n label: 'Accesorios',\n value: 'ACCESORIOS',\n detalles: 'la instalación de los accesorios',\n detallesPrevStep: 'Instalación de accesorios',\n },\n // { label: 'Chequeo', value: 'CHEQUEO', detalles: 'el chequeo de tu coche', detallesPrevStep: 'Chequeo' },\n { label: 'Otros', value: 'OTROS', detalles: 'el motivo de tu visita', detallesPrevStep: 'Visita' },\n];\n\n// LEM\n\nexport const CTAsTipoVisita = [\n {\n label: 'Una visita al concesionario',\n value: 'si visita',\n },\n { \n label: 'Una llamada', \n value: 'si llamada'\n },\n { \n label: 'Una videollamada', \n value: 'si videollamada'\n },\n];\n\nexport const CTAsTipoVisitaNo = [\n {\n label: 'No ha hecho falta',\n value: 'no ha hecho falta',\n },\n {\n label: 'No, pero me hubiera gustado',\n value: 'no pero me hubiera gustado',\n },\n];\n\nexport const periodoContactoOptions = [\n {\n value: '8_horas',\n label: 'En las primeras 8 horas',\n },\n {\n value: '24_horas',\n label: 'En las primeras 24 horas',\n },\n {\n value: 'mas_24_horas',\n label: 'En más de 24 horas',\n },\n];\n\n//No compra\n\nexport const CTAsMotivoNoQuiero = [\n {\n label: 'Coche compartido (car sharing o moto sharing)',\n value: 'car-sharing',\n },\n {\n label: 'Transporte público',\n value: 'transporte-publico',\n },\n {\n label: 'Patinete - Moto - Bicicleta',\n value: 'patinete-moto-bicicleta',\n },\n {\n label: 'Más adelante, en coche',\n value: 'coche',\n },\n {\n label: 'Otros',\n value: 'otros',\n },\n];\n\nexport const CTAsDudas = [\n { label: 'Los plazos de entrega', value: 'plazos' },\n { label: 'Tu visita al concesionario', value: 'experiencia' },\n { label: 'El precio del modelo', value: 'precio' },\n { label: 'El equipamiento y los asistentes adicionales', value: 'equipamiento' },\n { label: 'El consumo del modelo', value: 'consumo' },\n { label: 'La garantía del modelo', value: 'garantia' },\n { label: 'Las condiciones de financiación', value: 'financiación' },\n { label: 'La situación actual', value: 'situacion' },\n { label: 'Otros motivos', value: 'otros' },\n];\n\n//SAC\n\nexport const contactoOptionsSAC = [\n {\n value: 'EMAIL',\n label: 'Email',\n },\n {\n value: 'TELF',\n label: 'Teléfono',\n },\n // {\n // value: 'POSTAL',\n // label: 'Correo postal',\n // },\n {\n value: 'WHATSAPP',\n label: 'Whatsapp',\n },\n];\n\n//CEM postenta y CEM venta\n\nexport const ctaTestDrive = [\n { label: 'Sí y realicé la prueba', value: '1' },\n { label: 'Sí, pero no realicé la prueba', value: '2' },\n { label: 'No, pero estaba interesado/a ', value: '3' },\n { label: 'No y no estaba interesado/a', value: '4' },\n];\n\nexport const ctaDatosIncorrectos = [\n { label: 'Marca incorrecta', value: 'Marca' },\n { label: 'Modelo incorrecto', value: 'Modelo' },\n { label: 'Concesionario incorrecto', value: 'Instalación' },\n { label: 'Persona de contacto incorrecta', value: 'Contacto' },\n];\n\nexport const ctaDatosIncorrectosPosventa = [\n { label: 'Marca incorrecta', value: 'Marca' },\n { label: 'Modelo incorrecto', value: 'Modelo' },\n { label: 'Servicio Oficial', value: 'Instalación' },\n { label: 'Persona de contacto incorrecta', value: 'Contacto' },\n];\n\n \nexport const ctaAlternativaTransporte = [\n { label: 'Sí, un Volkswagen', value: '1' },\n { label: 'Sí, un coche de otra marca diferente a Volkswagen', value: '2' },\n { label: 'Sí, otra alternativa (transporte público, taxi, shuttle, …)', value: '3' },\n { label: 'No me ofreció ninguna', value: '4' },\n { label: 'Sin respuesta', value: '9' },\n];\nexport const ctaContactoSatisfaccion = [\n { label: 'Sí', value: '1' },\n { label: 'No', value: '2' },\n { label: 'Sin respuesta', value: '9' },\n];\n \nexport const ctaMotivoVisita = [\n\n { label: 'Revisión pre-ITV', value: '2' },\n { label: 'Avería circulando con el coche (fue necesario remolcarlo)', value: '4' },\n { label: 'Medida de servicio (excluida la medida de servicio diésel)', value: '10' },\n { label: 'Chapa y pintura', value: '6' },\n { label: 'Cambio de neumáticos', value: '3' },\n { label: 'Actualización de software', value: '11' },\n { label: 'Instalación de accesorios', value: '7' },\n { label: 'Servicio rutinario / de mantenimiento', value: '1' },\n { label: 'Otra visita inesperada (el coche pudo seguir circulando y elegiste tu Sercicio Oficial favorito)', value: '5' },\n { label: 'Otras reparaciones o reclamaciones (por ejemplo, problemas electrónicos)', value: '8' },\n { label: 'Sin respuesta', value: '99' },\n];\n\nexport const ctaEnviarRespuesta = [\n { label: 'Mis respuestas pueden ser enviadas junto a mi nombre', value: '1' },\n {\n label: 'Mis respuestas pueden ser enviadas pero sin mencionar mi nombre',\n extraInfo:\n 'Seleccionando esta opción, el concesionario no podrá ponerse en contacto contigo en relación a tus comentarios.',\n value: '2',\n },\n {\n label: 'Mis respuestas solo deben ser analizadas de manera anónima',\n extraInfo:\n 'Seleccionando esta opción, tus respuestas serán analizadas de modo agregado junto al resto de respuestas de todos los entrevistados y no se trasladarán a los comentarios abiertos.',\n value: '0',\n },\n];\nexport const ctaEnvioCEM = [\n {\n label:\n 'Sí, mis respuestas pueden ser publicadas de forma agregada sin mi nombre en la Web Oficial Volkswagen y en la de [Concesionario]',\n value: '1',\n },\n {\n label:\n 'No, mis respuestas no pueden ser publicadas de forma agregada en la Web Oficial Volkswagen y en la de [Concesionario]',\n value: '2',\n },\n];\n\n// No renovador\n\nexport const CTAsMotor = [\n {\n label: 'Gasolina',\n value: 'gasolina',\n }, \n {\n label: 'Diesel',\n value: 'diesel',\n },\n {\n label: 'Híbrido',\n value: 'híbrido',\n },\n {\n label: 'Eléctrico',\n value: 'electrico',\n },\n];\nexport const CTAsMotivoRenovadorYaTengo = [\n {\n label: 'Los plazos de entrega',\n value: 'plazos',\n },\n {\n label: 'El precio/opciones de financiación',\n value: 'precio/financiacion',\n },\n {\n label: 'El diseño del coche',\n value: 'diseño',\n },\n {\n label: 'El equipamiento del coche',\n value: 'equipamiento',\n },\n {\n label: 'Relación calidad/precio',\n value: 'relación calidad/precio',\n },\n {\n label: 'El consumo de combustible de los nuevos vehículos',\n value: 'consumo',\n },\n {\n label: 'La poca variedad de modelos y tecnologías disponibles',\n value: 'modelos',\n },\n {\n label: 'Mi experiencia con el concesionario de venta',\n value: 'experiencia venta',\n },\n {\n label: 'Mi experiencia previa con el servicio de posventa',\n value: 'experiencia posventa',\n },\n {\n label: 'Los costes de mantenimiento del vehículo anterior',\n value: 'costes mantenimiento',\n },\n {\n label: 'Las averías sufridas con el vehículo anterior',\n value: 'averías',\n },\n {\n label: 'Otras experiencias con la marca',\n value: 'marca',\n },\n {\n label: 'Otros motivos',\n value: 'otros motivos',\n },\n];\n\nexport const CTAsMotivoRenovadorNoTengo = [\n {\n label: 'Los plazos de entrega',\n value: 'plazos',\n },\n {\n label: 'El precio/opciones de financiación',\n value: 'precio/financiacion',\n },\n {\n label: 'El diseño del coche',\n value: 'diseño',\n },\n {\n label: 'El equipamiento del coche',\n value: 'equipamiento',\n },\n {\n label: 'Relación calidad/precio',\n value: 'relación calidad/precio',\n },\n {\n label: 'El consumo de combustible de los nuevos vehículos',\n value: 'consumo',\n },\n {\n label: 'La poca variedad de modelos y tecnologías disponibles',\n value: 'modelos',\n },\n {\n label: 'Mi experiencia con el concesionario de venta',\n value: 'experiencia venta',\n },\n {\n label: 'Mi experiencia previa con el servicio de posventa',\n value: 'experiencia posventa',\n },\n {\n label: 'Los costes de mantenimiento del vehículo anterior',\n value: 'costes mantenimiento',\n },\n {\n label: 'Las averías sufridas con el vehículo anterior',\n value: 'averías',\n },\n {\n label: 'Otras experiencias con la marca',\n value: 'marca',\n },\n {\n label: 'Otros motivos',\n value: 'otros motivos',\n },\n];\n\nexport const CTAsMotivoRenovadorNoTengoExclusivo = [\n {\n label: 'Nada',\n value: 'nada',\n },\n];\n\nexport const CTAsUsadoNuevo = [\n {\n label: 'Vehículo Nuevo',\n value: 'Vehículo Nuevo',\n },\n {\n label: 'Vehículo Usado',\n value: 'Vehículo Usado',\n },\n];\n\nexport const CTAsLugarCompra = [\n {\n label: 'Concesionario oficial',\n value: 'Concesionario oficial',\n },\n {\n label: 'Concesionario no oficial',\n value: 'Concesionario no oficial',\n },\n {\n label: 'Empresa de Renting/Leasing',\n value: 'Empresa de Renting/Leasing',\n },\n {\n label: 'Compra-venta privada',\n value: 'Compra-venta privada',\n },\n];\n\nexport const CTAsNuevoOcasión = [\n {\n label: 'Uno nuevo',\n value: 'nuevo',\n },\n {\n label: 'Uno de ocasión',\n value: 'ocasión',\n },\n];\n\nexport const CTAsFormasMovilidad = [\n {\n label: 'Coche compartido (car sharing o moto sharing)',\n value: 'Car Sharing Moto Sharing',\n },\n {\n label: 'Transporte público',\n value: 'Transporte público',\n },\n {\n label: 'Patinete',\n value: 'Patinete',\n },\n {\n label: 'Moto',\n value: 'Moto',\n },\n {\n label: 'Bicicleta',\n value: 'Bicicleta',\n },\n {\n label: 'Otros',\n value: 'Otros',\n },\n];\nexport const CTAsFormasMovilidadExclusive = [\n {\n label: 'No tengo necesidad de utilizar ningún medio de transporte para desplazarme',\n value: 'No tengo necesidad',\n },\n];\nexport const CTAsRazones = [\n {\n label: 'Económicas',\n value: 'Económicas',\n },\n {\n label: 'Medioambientales',\n value: 'Medioambientales',\n },\n {\n label: 'Ahorro de tiempo',\n value: 'Ahorro de tiempo',\n },\n {\n label: 'Otras razones',\n value: 'Otros',\n },\n];\n\n//BAJA COMUNICACIONES\n\nexport const questionTwoOptions = [\n { label: 'Ya no me interesa el contenido',\n value: 'No Interés'\n },\n { label: 'Recibo demasiadas comunicaciones vuestras',\n value: 'Demasiadas Comunicaciones'\n },\n { label: 'Tengo otras razones',\n value: 'Otros Motivos'\n },\n];\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var ReactIs = require('react-is');\n\n // By explicitly using `prop-types` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(ReactIs.isElement, throwOnDirectAccess);\n} else {\n // By explicitly using `prop-types` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n","import { useEffect, useState } from 'react';\nimport { Points } from 'src/types';\n\nexport const usePinState = (selectedPoint: Points, hoverPoint: Points, point: Points) => {\n const [isActive, setIsActive] = useState(false);\n const [isHover, setIsHover] = useState(false);\n\n useEffect(() => {\n if (selectedPoint) {\n if (isCluster(point)) {\n sameClusterId(selectedPoint, point) ? setIsActive(true) : setIsActive(false);\n } else {\n sameKvps(selectedPoint, point) ? setIsActive(true) : setIsActive(false);\n }\n }\n\n if (hoverPoint) {\n if (window.innerWidth < 959) {\n // Hover solo se aplica a desktop\n setIsHover(false);\n } else {\n if (isCluster(point)) {\n sameClusterId(hoverPoint, point) ? setIsHover(true) : setIsHover(false);\n } else {\n sameKvps(hoverPoint, point) ? setIsHover(true) : setIsHover(false);\n }\n }\n }\n }, [selectedPoint, hoverPoint]);\n\n return { isActive, isHover };\n};\n\nconst isCluster = (point: Points) => point.properties.cluster;\n\nconst sameClusterId = (selectedPoint: Points, point: Points) => {\n if (selectedPoint.properties.parent_cluster_id && point.id) {\n return selectedPoint.properties.parent_cluster_id === point.id;\n }\n return false;\n};\nconst sameKvps = (selectedPoint: Points, point: Points) => {\n if (\n selectedPoint.properties &&\n selectedPoint.properties.dealer &&\n point.properties &&\n point.properties.dealer &&\n selectedPoint.properties.dealer.kvps === point.properties.dealer.kvps\n ) {\n return true;\n }\n return false;\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { debounce } from 'src/feature-app';\n\nexport function useAddressPredictions(input: string, selectedValue: boolean): any[] {\n\n \n const [predictions, setPredictions] = useState([]);\n\n const autocomplete = useRef();\n\n if (!autocomplete.current && window.google) {\n autocomplete.current = new window.google.maps.places.AutocompleteService();\n }\n\n async function getPlacePredictions(input: string) {\n await autocomplete.current.getPlacePredictions(\n { input, types: ['geocode'], componentRestrictions: { country: 'es' } },\n (predictions) => {\n // El type regions también devuelve como resultado el país, por lo que hay que filtrarlo.\n if (predictions) {\n predictions = predictions.filter((prediction) => !prediction.types.includes('country'));\n setPredictions(predictions.map((prediction) => prediction.description));\n }\n }\n );\n }\n\n const debouncedGetPlacePredictions = useCallback(debounce(getPlacePredictions, 500), []);\n\n useEffect(() => {\n if (!selectedValue && input.length > 2) {\n debouncedGetPlacePredictions(input);\n }\n }, [input]);\n\n return predictions;\n}\n","import { checkIfMidDay, checkIfMorning, getNormalizedDate } from 'src/feature-app/NewMap';\nimport {\n getYYYYMMDDx, \n hourAndMinute,\n} from 'src/feature-app';\n\nexport const getFranjaAndDayFrom = (from: number): { day: string; franjaHoraria: 'Mañana' | 'Mediodía' | 'Tarde' } => {\n const day = getYYYYMMDDx(Number(from));\n const hour = hourAndMinute(from);\n const normalizdedDate = getNormalizedDate(hour);\n const franjaHoraria = checkIfMorning(normalizdedDate)\n ? 'Mañana'\n : checkIfMidDay(normalizdedDate)\n ? 'Mediodía'\n : 'Tarde';\n\n return { day, franjaHoraria };\n};\n","import {\n Assessors,\n Slot,\n} from 'src/types';\nimport dayjs from 'dayjs';\n\n\nexport const createNoDmsSlotAndAssessor = (franjaHoraria: string, day: string): { slot: Slot; assessor: Assessors } => {\n const from = Number(dayjs.utc(`${day} 01:00`, 'YYYY-MM-DD HH:mm').format('x'));\n const to = Number(dayjs.utc(`${day} 23:59`, 'YYYY-MM-DD HH:mm').format('x'));\n const code = franjaHoraria === 'Mañana' ? 'MANANA' : franjaHoraria === 'Mediodía' ? 'MEDIODIA' : 'TARDE';\n const assessor: Assessors = { code: '0', name: 'Todos' };\n const slot: Slot = {\n from,\n to,\n replacementCarServiceAvailable: false,\n dayMoment: {\n code,\n name: franjaHoraria,\n },\n assessorCode: '0',\n };\n\n return { slot, assessor };\n};\n","import {\n Breakpoints,\n Container,\n ContainerHorizontalAlignment,\n ContainerPadding,\n ContainerVerticalAlignment,\n ContainerWrap,\n CTA,\n Layout,\n styled,\n Text,\n TextAlignment,\n TextAppearance,\n TextColor,\n ThemeProvider\n} from '@volkswagen-onehub/components-core';\nimport { Calendar, FleetServicePrivate, CarPickupService } from 'src/icons-core-imports';\nimport React, { useEffect, useState } from 'react';\nimport { useSelector } from 'react-redux';\nimport { useMapGeneralController } from 'src/feature-app';\nimport { Points } from 'src/types';\nimport { Horario, OneFormState } from 'src/types';\nimport { getDistanceFromLatLngCenter } from 'src/feature-app/NewMap';\nimport { useTrackingManager } from 'src/feature-app/hooks/use-tracking-manager';\nimport { usePinState } from 'src/feature-app/NewMap/usePinState';\n\ninterface BoxCardProps {\n selected?: boolean;\n isCarousel: boolean;\n isHover?: boolean;\n isFirstDesktop?: boolean;\n greyCard?: boolean;\n}\n\nconst BoxCard = styled.div
`\n width: 100%;\n margin-top: ${(props) => (props.isCarousel || props.isFirstDesktop ? '0' : '20px')};\n padding: ${(props) => (props.isCarousel ? '12px' : '20px')};\n border: ${(props) =>\n props.selected && props.greyCard && !props.isCarousel \n ? '2px solid #6A767D' \n : props.greyCard && !props.isCarousel \n ? '1px solid #6A767D'\n :props.selected && !props.isCarousel\n ? '2px solid #FFFFFF'\n : props.isCarousel\n ? 'none'\n : '1px solid rgba(255,255,255,0.44)'};\n :hover {\n border: ${(props) => (\n props.isCarousel \n ? 'none'\n : props.selected && props.greyCard\n ? '2px solid #6A767D' \n : props.greyCard\n ? '1px solid #6A767D'\n : props.selected\n ? '2px solid #FFFFFF' \n : '1px solid #4cc7f4')};\n }\n\n @media all and (min-width: 560px) {\n margin-top: ${(props) => (props.isCarousel || props.isFirstDesktop ? '0' : '24px')};\n padding: 20px;\n }\n @media screen and (min-width: 960px) {\n .main {\n border: ${(props) =>\n props.isCarousel\n ? 'none'\n : props.selected\n ? '2px solid #001e50;'\n : props.isHover\n ? '1px solid #0040C5'\n : '1px solid #DFE4E8'};\n }\n .inverted {\n border: ${(props) =>\n props.isCarousel\n ? 'none'\n : props.selected\n ? '2px solid #FFFFFF'\n : props.isHover\n ? '1px solid #4cc7f4'\n : '1px solid rgba(255,255,255,0.44)'};\n }\n \n }\n @media all and (min-width: 1600px) {\n margin-top: ${(props) => (props.isCarousel || props.isFirstDesktop ? '0' : '28px')};\n }\n`;\n\ninterface isCarouselProps {\n isCarousel: boolean;\n}\n\nconst CTAVerMasHorasWrapper = styled.div`\n button {\n color: #ffffff;\n font-size: ${(props) => (props.isCarousel ? '12px' : null)};\n svg {\n height: ${(props) => (props.isCarousel ? '10px' : null)};\n width: ${(props) => (props.isCarousel ? '10px' : null)};\n }\n }\n`;\n\nconst EllipsisTextWrapper = styled.p<{greyCard?: boolean}>`\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: 0px;\n margin-bottom: 0px;\n color: ${(props)=>(props.greyCard ? '#6A767D' : '#FFFFFF')};\n`;\nconst GreyText = styled.span<{greyCard?: boolean}>`\n color: ${(props)=>(props.greyCard ? '#6A767D' : '#FFFFFF')};\n`;\nconst SVGSize = styled.div<{greyCard: boolean}>`\n padding-left: 16px;\n svg {\n height: 20px;\n width: auto;\n color: ${(props)=> props.greyCard ? '#6A767D' : '#FFFFFF'};\n }\n`;\nconst CustomCTA = styled.button<{greyCard?: boolean}>`\n height: 32px;\n width: max-content;\n padding: 8px 16px;\n border: none;\n cursor: pointer;\n border-radius: 22px;\n display: flex;\n align-items: center;\n background-color: ${(props)=> props.greyCard ? '#6A767D' : '#FFFFFF'};\n color: ${(props)=> props.greyCard ? '#DFE4E8' : '#001E50'};\n :hover {\n background-color: ${(props)=> props.greyCard ? '#6A767D' : 'rgba(255,255,255,0.90)'};\n }\n`;\nconst CustomTerciayCTA = styled.button<{greyCard?: boolean}>`\n color: ${(props)=> props.greyCard ? '#6A767D' : '#FFFFFF'};\n display: flex;\n border: none;\n cursor: pointer;\n background: none;\n align-items: center;\n padding:0 0 2px;\n border-bottom: ${(props)=> props.greyCard ? '1px solid #6A767D' : '1px solid #FFFFFF'};\n :hover {\n background-color: ${(props)=> props.greyCard ? '#6A767D' : 'rgba(255,255,255,0.90)'};\n }\n svg{\n color: ${(props)=> props.greyCard ? '#6A767D' : '#FFFFFF'};\n }\n div {\n color: ${(props)=> props.greyCard ? '#6A767D' : '#FFFFFF'};\n }\n`;\n\ninterface DealerCardProps {\n distanceFromCenter: string;\n handleSeleccionarOnClick?: any;\n handleShowCalendarOnClick?: any;\n // center?: Center,\n isCarousel: boolean;\n dealerInfo: any;\n point: Points;\n slots: any;\n handleShowSlots?: (point: Points) => string | null;\n isCitaPosventa?: boolean;\n isFirstDesktop?: boolean;\n carPickupSelected?: boolean;\n replacementCarSelected?: boolean;\n}\n\nexport const NewDealerCard = React.memo((props: DealerCardProps) => {\n const { \n distanceFromCenter, \n isCarousel, \n dealerInfo, \n point, \n handleShowSlots, \n isCitaPosventa,\n isFirstDesktop,\n carPickupSelected,\n replacementCarSelected\n } = props;\n\n const { suggestionIsAddress } = useSelector((state: OneFormState) => state.formInfo);\n const dealerCompletAdress = `${dealerInfo.markerInfo.dealerInfo.address}, ${dealerInfo.markerInfo.dealerInfo.zipCode} ${dealerInfo.markerInfo.dealerInfo.city}`;\n const {\n centerToCalculateDistance,\n handlePointClickAndCarouselMove,\n handleHoverPoint,\n hoverPoint,\n selectedPoint,\n userIsGeoLocated,\n handleClusterClick,\n } = useMapGeneralController();\n\n const { isActive, isHover } = usePinState(selectedPoint, hoverPoint, point);\n\n const [ greyCard, setGreyCard ] = useState(false);\n\n useEffect(()=>{\n if(point) {\n if(carPickupSelected && !point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ){\n setGreyCard(true);\n } else if(replacementCarSelected && !point.properties.dealer.dmsInfo.replacementCarServiceAvailable) {\n setGreyCard(true);\n } else {\n setGreyCard(false);\n }\n } \n }, [carPickupSelected, replacementCarSelected, point]);\n\n return (\n {\n e.preventDefault();\n if (point.properties.parent_cluster_id) {\n if (window.innerWidth <= 959) {\n handleClusterClick(point, true, true);\n } else {\n handleClusterClick(point, true);\n }\n } else {\n handlePointClickAndCarouselMove(point);\n }\n }}\n onMouseEnter={(e) => {\n if (!isCarousel) {\n e.preventDefault();\n handleHoverPoint(point);\n }\n }}\n onMouseLeave={(e) => {\n if (!isCarousel) {\n e.preventDefault();\n handleHoverPoint(null);\n }\n }}\n >\n \n {isCarousel ? (\n <>\n {/*card para el carousel*/}\n
\n \n {\n userIsGeoLocated || suggestionIsAddress ? (\n \n \n {dealerInfo.name ? dealerInfo.name : null} \n \n\n \n \n {userIsGeoLocated || suggestionIsAddress\n ? distanceFromCenter\n ? `${distanceFromCenter}km`\n : `${getDistanceFromLatLngCenter(centerToCalculateDistance.current, point)}km`\n : null}\n \n \n \n ) : (\n \n {dealerInfo.name ? dealerInfo.name : null} \n \n )\n }\n
\n \n {!point.properties.dealer.dmsInfo || !point.properties.dealer.dmsInfo.dmsAvailable ? (\n \n {dealerCompletAdress} \n
\n ) : (\n {dealerCompletAdress} \n )}\n \n \n\n {handleShowSlots ? (\n handleShowSlots(point) === null ? (\n <>\n {\n point.properties.dealer.dmsInfo ? (\n
\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n \n ) :
\n }\n >\n ) : (\n
\n \n \n {handleShowSlots(point)}\n \n \n {\n point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.replacementCarServiceAvailable\n || point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.pickupCarServiceAvailabe \n ? (\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n ) : null\n }\n \n )\n ) : (\n <>\n { point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.replacementCarServiceAvailable\n || point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.pickupCarServiceAvailabe \n ? (\n
\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n \n ) : null\n }\n >\n )}\n >\n ) : (\n <>\n {/*card para los tabs, cualquier breakpoint*/}\n
\n \n {\n userIsGeoLocated || suggestionIsAddress ? (\n \n \n \n {dealerInfo.name ? dealerInfo.name : null}\n \n \n \n \n {userIsGeoLocated || suggestionIsAddress\n ? distanceFromCenter\n ? `${distanceFromCenter}km`\n : `${getDistanceFromLatLngCenter(centerToCalculateDistance.current, point)}km`\n : null}\n \n \n \n ) : (\n \n \n {dealerInfo.name ? dealerInfo.name : null}\n \n \n )\n }\n
\n \n \n \n {dealerCompletAdress}\n \n
\n \n \n\n {handleShowSlots ? (\n handleShowSlots(point) === null ? (\n <>\n {\n point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.replacementCarServiceAvailable\n || point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.pickupCarServiceAvailabe \n ? (\n
\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n \n ) : null\n }\n >\n ) : (\n
\n \n \n {handleShowSlots(point)}\n \n \n {\n point.properties.dealer.dmsInfo ? (\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n ) : null\n }\n \n )\n ) : (\n <>\n {\n point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.replacementCarServiceAvailable\n || point.properties.dealer.dmsInfo && point.properties.dealer.dmsInfo.pickupCarServiceAvailabe \n ? (\n
\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n \n ) : null\n }\n >\n )}\n >\n )}\n {isCitaPosventa ? (
):
}\n
\n \n );\n});\n\nconst CitaPosventaCTAs = (props: DealerCardProps) => {\n const { \n handleSeleccionarOnClick, \n handleShowCalendarOnClick, \n isCarousel, \n dealerInfo, \n point,\n carPickupSelected,\n replacementCarSelected \n } = props;\n\n const trackingManager = useTrackingManager();\n\n const { formData } = useSelector((state: OneFormState) => state);\n const { horario }: { horario?: Horario } = formData.fields;\n\n const [ greyCard, setGreyCard ] = useState(false);\n\n useEffect(()=>{\n if(point) {\n if(carPickupSelected && !point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ){\n setGreyCard(true);\n } else if(replacementCarSelected && !point.properties.dealer.dmsInfo.replacementCarServiceAvailable) {\n setGreyCard(true);\n } else {\n setGreyCard(false);\n }\n } \n }, [carPickupSelected, replacementCarSelected, point]);\n\n return !dealerInfo.dmsInfo || !dealerInfo.dmsInfo.dmsAvailable ? (\n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick(\n {\n contentId: 'Ver horario',\n },\n dealerInfo\n );\n\n handleShowCalendarOnClick(point);\n }}\n >\n \n Ver calendario\n \n \n {\n point.properties.dealer.dmsInfo ? (\n \n {\n point.properties.dealer.dmsInfo.replacementCarServiceAvailable ? (\n \n \n \n ) : null\n }\n {\n point.properties.dealer.dmsInfo.pickupCarServiceAvailabe ? (\n \n \n \n ) : null\n }\n
\n ) : null\n }\n \n ) : (\n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick(\n {\n contentId: 'Seleccionar',\n },\n dealerInfo\n );\n\n handleSeleccionarOnClick(point);\n }}\n >\n \n Seleccionar\n \n \n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick(\n {\n contentId: 'Ver más horas',\n },\n dealerInfo\n );\n handleShowCalendarOnClick(point);\n }}\n >\n \n \n \n Ver más horas\n \n
\n \n \n \n );\n};\n\nconst LeadsCTAs = (props: DealerCardProps) => {\n const { handleSeleccionarOnClick, dealerInfo, point } = props;\n\n const trackingManager = useTrackingManager();\n\n return (\n \n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick(\n {\n contentId: 'Seleccionar',\n },\n dealerInfo\n );\n\n handleSeleccionarOnClick(point);\n }}\n >\n Seleccionar\n \n \n \n );\n};\n","import React, { useEffect, useState } from 'react';\nimport {\n styled,\n Layout,\n Breakpoints,\n} from '@volkswagen-onehub/components-core';\nimport { Points } from 'src/types';\nimport { useMapGeneralController } from 'src/feature-app';\nimport { SelectedTab } from 'src/types';\n\nconst TabsWrapper = styled.div`\n width: 100%;\n height: 100%;\n padding-left: 5px;\n padding-top: 5px;\n @media all and (min-width: 960px) {\n /* width: 380px; */\n /* Falta ver como se comporta este width: 100% con el scroll */\n width: 100%;\n }\n\n & > div {\n @media all and (min-width: 960px) {\n height: calc(100vh - 174px);\n overflow-y: auto;\n padding-bottom: 24px;\n }\n @media all and (min-width: 1600px) {\n height: calc(100vh - 200px);\n }\n }\n`;\n\nconst WidthWrapper = styled.div`\n width: 100vw;\n @media all and (min-width: 960px) {\n width: 100%;\n }\n`;\n\ninterface SeleccionDealerTabsProps {\n pointsByDistance?: Points[];\n pointsByTime?: Points[];\n isTimeSelected?: boolean;\n setIsTimeSelected?: React.Dispatch>;\n renderPoints: (points: Points[], isTime?: boolean) => JSX.Element[];\n setPreSelectedOrderValue?: React.Dispatch>;\n preSelectedOrderValue?: string;\n pointsToList: Points[];\n}\n\nexport function SeleccionDealerTabs(props: SeleccionDealerTabsProps) {\n const {\n pointsByDistance,\n pointsByTime,\n isTimeSelected,\n setIsTimeSelected,\n renderPoints,\n setPreSelectedOrderValue,\n preSelectedOrderValue,\n pointsToList,\n } = props;\n const { clusters } = useMapGeneralController();\n\n const [defaultIndex, setDefaultIndex] = useState(0);\n\n useEffect(() => {\n if (preSelectedOrderValue && preSelectedOrderValue === 'horario') {\n setDefaultIndex(1);\n } else {\n setDefaultIndex(0);\n }\n }, [preSelectedOrderValue]);\n\n return (\n \n \n {renderPoints(pointsToList, true)}\n\n {/* \n \n Ordenar por:\n \n */}\n\n {/* \n {\n setDefaultIndex(index);\n if (index === 0) {\n setPreSelectedOrderValue('ubicacion');\n } else {\n setPreSelectedOrderValue('horario');\n }\n }}\n defaultIndex={defaultIndex}\n >\n {{\n title: 'Ubicación',\n content: renderPoints(pointsToList, false),\n key: 'ubicacion',\n }}\n {{ title: 'Horario', content: renderPoints(pointsToList, true), key: 'horario' }}\n \n */}\n \n \n );\n}\n","import { styled } from '@volkswagen-onehub/components-core';\nimport { css } from 'styled-components';\n\ninterface styledWrapperProps { \n notALayer?: boolean;\n isFiltrosSuggest: boolean;\n isLocating?: boolean;\n inputFocus?: boolean;\n formTheme?: string;\n isModeloSuggest?: boolean;\n isFullScreen?: boolean;\n goUp?: boolean;\n autoWidth?: boolean;\n}\n\n\nexport const MagnifierLabel = styled.div`\n color: ${(props) => (props.isFiltrosSuggest || props.formTheme === 'main' ? '#001e50' : '#ffffff')};\n padding-right: 8px;\n display: flex;\n align-items: center;\n\n & svg {\n fill: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n }\n`;\nexport const CloseButton = styled.button`\n cursor: pointer;\n border: none;\n outline: none;\n background: transparent;\n padding-left: 8px;\n display: flex;\n align-items: center;\n\n & svg {\n fill: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n }\n`;\n\nexport const StyledWrapper = styled.div`\n display: flex;\n justify-content: flex-start;\n margin-top: ${(props) => (props.isFiltrosSuggest ? '24px' : null)};\n box-shadow: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '0px 1px 0px 0px #dfe4e8'\n : '0px 1px 0px 0px #6A767D'\n : props.inputFocus\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '0 2px 0 0 #001E50'\n : '0 2px 0 0 #00B0F0'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '0px 1px 0px 0px #001E50'\n : '0px 1px 0px 0px #ffffff'};\n\n & .react-autosuggest__container {\n width: 100%;\n }\n\n & .react-autosuggest__input {\n width: 100%;\n padding: 8px 0;\n border: none;\n background-color: ${(props) => (props.isFiltrosSuggest || props.formTheme === 'main' ? '#ffffff' : '#001e50')};\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n /* Añadir puntos suspensivos para el placeholder en mobile */\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n /* WebKit, Edge */\n ::-webkit-input-placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n }\n /* Firefox 4-18 */\n :-moz-placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n opacity: 1;\n }\n /* Firefox 19+ */\n ::-moz-placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n opacity: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n }\n /* IE 10-11 */\n :-ms-input-placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n }\n /* Edge */\n ::-ms-input-placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n }\n /* MODERN BROWSER */\n ::placeholder {\n color: ${(props) =>\n props.isLocating\n ? props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#dfe4e8'\n : '#6A767D'\n : props.isFiltrosSuggest || props.formTheme === 'main'\n ? '#001e50'\n : '#ffffff'};\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n }\n }\n\n & .react-autosuggest__input--focused {\n outline: none;\n }\n\n & .react-autosuggest__input--open {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n & .react-autosuggest__suggestions-container {\n display: none;\n width: 100%;\n }\n\n & .react-autosuggest__suggestions-container--open {\n display: block;\n position: absolute;\n height: max-content;\n border: 1px solid #aaa;\n background-color: #fff; \n font-family: Helvetica, sans-serif;\n font-weight: 300;\n font-size: 16px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n z-index: 1060;\n overflow: hidden;\n border: none;\n box-shadow: 0px 12px 24px 0px rgba(0, 0, 0, 0.12);\n\n left: 0;\n top: ${(props)=>props.goUp ? '0' : '36px'};\n transform: ${(props)=>props.goUp ? 'translateY(-100%)' : null};\n \n ${(props) =>\n props.isFiltrosSuggest\n ? css`\n width: calc( 100% + 68x); \n @media screen and (min-width: 960px) {\n width: 400px; \n }\n `\n : props.isModeloSuggest ?\n css`\n width: var(--size-grid020);\n @media all and (min-width: 560px) {\n width: ${(props) => (props.notALayer ? 'var(--size-grid013)' : '303px')};\n }\n @media all and (min-width: 960px) {\n width: ${(props) => (props.notALayer ? 'var(--size-grid008)' : '320px')};\n }\n @media all and (min-width: 1280px) {\n width: ${(props) => (props.notALayer ? 'var(--size-grid006)' : '320px')};\n }\n @media all and (min-width: 1920px) {\n width: ${(props) => (props.notALayer ? 'var(--size-grid005)' : '320px')};\n }\n @media all and (min-width: 2560px) {\n width: ${(props) => (props.notALayer ? 'var(--size-grid004)' : '320px')};\n } \n `\n : props.isFullScreen ? \n css`\n width: var(--size-grid020);\n @media all and (min-width: 960px) {\n width: ${(props) => (props.autoWidth ? '100%' : 'var(--size-grid013)')};\n }\n @media all and (min-width: 1280px) {\n width:${(props) => (props.autoWidth ? '100%' : 'var(--size-grid014)')};\n }\n @media all and (min-width: 1920px) {\n width: ${(props) => (props.autoWidth ? '100%' : 'var(--size-grid012)')};\n }\n @media all and (min-width: 2560px) {\n width: ${(props) => (props.autoWidth ? '100%' : 'var(--size-grid010)')};\n }\n `\n :css`\n width: calc( 100% + 68x); \n @media screen and (min-width: 960px) {\n width: 720px;\n }\n `}\n }\n\n & .react-autosuggest__suggestions-list {\n margin: 0;\n padding: 0;\n list-style-type: none;\n overflow: hidden scroll;\n height: max-content;\n max-height: 170px;\n @media all and (min-height: 500px) {\n max-height: 230px;\n }\n @media all and (min-height: 800px) {\n max-height: 300px;\n }\n @media all and (min-height: 800px) {\n max-height: 350px;\n }\n }\n\n & .react-autosuggest__suggestion {\n cursor: pointer;\n padding: 10px 20px;\n left: 0;\n :hover {\n * {\n color: #0040c5;\n }\n svg {\n fill: #0040c5;\n }\n }\n }\n\n & .react-autosuggest__suggestion--highlighted {\n /* background-color: #ddd; */\n }\n`;\n\nexport const SuggestionWrapper = styled.div`\n width: 100%;\n display: flex;\n align-items: flex-start;\n text-align: left;\n color: #001e50;\n`;\n","'use strict';\n\n// do not edit .js files directly - edit src/index.jst\n\n\n\nmodule.exports = function equal(a, b) {\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0;)\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0;) {\n var key = keys[i];\n\n if (!equal(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a!==a && b!==b;\n};\n","/**\n * Copyright 2019 Google LLC. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at.\n *\n * Http://www.apache.org/licenses/LICENSE-2.0.\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport isEqual from \"fast-deep-equal\";\n\n/**\n * @ignore\n */\ndeclare global {\n interface Window {\n __googleMapsCallback: (e: Event) => void;\n }\n}\n\nexport const DEFAULT_ID = \"__googleMapsScriptId\";\n\ntype Libraries = (\n | \"drawing\"\n | \"geometry\"\n | \"localContext\"\n | \"places\"\n | \"visualization\"\n)[];\n\n/**\n * The Google Maps JavaScript API\n * [documentation](https://developers.google.com/maps/documentation/javascript/tutorial)\n * is the authoritative source for [[LoaderOptions]].\n/**\n * Loader options\n */\nexport interface LoaderOptions {\n /**\n * See https://developers.google.com/maps/documentation/javascript/get-api-key.\n */\n apiKey: string;\n /**\n * @deprecated See https://developers.google.com/maps/premium/overview.\n */\n channel?: string;\n /**\n * @deprecated See https://developers.google.com/maps/premium/overview, use `apiKey` instead.\n */\n client?: string;\n /**\n * In your application you can specify release channels or version numbers:\n *\n * The weekly version is specified with `version=weekly`. This version is\n * updated once per week, and is the most current.\n *\n * ```\n * const loader = Loader({apiKey, version: 'weekly'});\n * ```\n *\n * The quarterly version is specified with `version=quarterly`. This version\n * is updated once per quarter, and is the most predictable.\n *\n * ```\n * const loader = Loader({apiKey, version: 'quarterly'});\n * ```\n *\n * The version number is specified with `version=n.nn`. You can choose\n * `version=3.40`, `version=3.39`, or `version=3.38`. Version numbers are\n * updated once per quarter.\n *\n * ```\n * const loader = Loader({apiKey, version: '3.40'});\n * ```\n *\n * If you do not explicitly specify a version, you will receive the\n * weekly version by default.\n */\n version?: string;\n /**\n * The id of the script tag. Before adding a new script, the Loader will check for an existing one.\n */\n id?: string;\n /**\n * When loading the Maps JavaScript API via the URL you may optionally load\n * additional libraries through use of the libraries URL parameter. Libraries\n * are modules of code that provide additional functionality to the main Maps\n * JavaScript API but are not loaded unless you specifically request them.\n *\n * ```\n * const loader = Loader({\n * apiKey,\n * libraries: ['drawing', 'geometry', 'places', 'visualization'],\n * });\n * ```\n *\n * Set the [list of libraries](https://developers.google.com/maps/documentation/javascript/libraries) for more options.\n */\n libraries?: Libraries;\n /**\n * By default, the Maps JavaScript API uses the user's preferred language\n * setting as specified in the browser, when displaying textual information\n * such as the names for controls, copyright notices, driving directions and\n * labels on maps. In most cases, it's preferable to respect the browser\n * setting. However, if you want the Maps JavaScript API to ignore the\n * browser's language setting, you can force it to display information in a\n * particular language when loading the Maps JavaScript API code.\n *\n * For example, the following example localizes the language to the United\n * Kingdom:\n *\n * ```\n * const loader = Loader({apiKey, language: 'ja', region: 'JP'});\n * ```\n *\n * See the [list of supported\n * languages](https://developers.google.com/maps/faq#languagesupport). Note\n * that new languages are added often, so this list may not be exhaustive.\n *\n */\n language?: string;\n /**\n * When you load the Maps JavaScript API from maps.googleapis.com it applies a\n * default bias for application behavior towards the United States. If you\n * want to alter your application to serve different map tiles or bias the\n * application (such as biasing geocoding results towards the region), you can\n * override this default behavior by adding a region parameter when loading\n * the Maps JavaScript API code.\n *\n * The region parameter accepts Unicode region subtag identifiers which\n * (generally) have a one-to-one mapping to country code Top-Level Domains\n * (ccTLDs). Most Unicode region identifiers are identical to ISO 3166-1\n * codes, with some notable exceptions. For example, Great Britain's ccTLD is\n * \"uk\" (corresponding to the domain .co.uk) while its region identifier is\n * \"GB.\"\n *\n * For example, the following example localizes the map to the United Kingdom:\n *\n * ```\n * const loader = Loader({apiKey, region: 'GB'});\n * ```\n */\n region?: string;\n /**\n * (Beta) You can add multiple Map IDs to your map using the map_ids paramenter in\n * your bootstrap request.\n */\n mapIds?: string[];\n /**\n * Use a custom url and path to load the Google Maps API script.\n */\n url?: string;\n /**\n * Use a cryptographic nonce attribute.\n */\n nonce?: string;\n /**\n * The number of script load retries.\n */\n retries?: number;\n}\n\n/**\n * [[Loader]] makes it easier to add Google Maps JavaScript API to your application\n * dynamically using\n * [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).\n * It works by dynamically creating and appending a script node to the the\n * document head and wrapping the callback function so as to return a promise.\n *\n * ```\n * const loader = new Loader({\n * apiKey: \"\",\n * version: \"weekly\",\n * libraries: [\"places\"]\n * });\n *\n * loader.load().then(() => {\n * const map = new google.maps.Map(...)\n * })\n * ```\n */\nexport class Loader {\n /**\n * See [[LoaderOptions.version]]\n */\n version: string;\n /**\n * See [[LoaderOptions.apiKey]]\n */\n apiKey: string;\n /**\n * See [[LoaderOptions.channel]]\n */\n channel: string;\n /**\n * See [[LoaderOptions.client]]\n */\n client: string;\n /**\n * See [[LoaderOptions.id]]\n */\n id: string;\n /**\n * See [[LoaderOptions.libraries]]\n */\n libraries: Libraries;\n /**\n * See [[LoaderOptions.language]]\n */\n language: string;\n\n /**\n * See [[LoaderOptions.region]]\n */\n region: string;\n\n /**\n * See [[LoaderOptions.mapIds]]\n */\n mapIds: string[];\n\n /**\n * See [[LoaderOptions.nonce]]\n */\n nonce: string | null;\n\n /**\n * See [[LoaderOptions.retries]]\n */\n retries: number;\n\n /**\n * See [[LoaderOptions.url]]\n */\n url: string;\n\n private CALLBACK = \"__googleMapsCallback\";\n private callbacks: ((e: Event) => void)[] = [];\n private done = false;\n private loading = false;\n private onerrorEvent: Event;\n private static instance: Loader;\n private errors: ErrorEvent[] = [];\n\n /**\n * Creates an instance of Loader using [[LoaderOptions]]. No defaults are set\n * using this library, instead the defaults are set by the Google Maps\n * JavaScript API server.\n *\n * ```\n * const loader = Loader({apiKey, version: 'weekly', libraries: ['places']});\n * ```\n */\n constructor({\n apiKey,\n channel,\n client,\n id = DEFAULT_ID,\n libraries = [],\n language,\n region,\n version,\n mapIds,\n nonce,\n retries = 3,\n url = \"https://maps.googleapis.com/maps/api/js\",\n }: LoaderOptions) {\n this.version = version;\n this.apiKey = apiKey;\n this.channel = channel;\n this.client = client;\n this.id = id || DEFAULT_ID; // Do not allow empty string\n this.libraries = libraries;\n this.language = language;\n this.region = region;\n this.mapIds = mapIds;\n this.nonce = nonce;\n this.retries = retries;\n this.url = url;\n\n if (Loader.instance) {\n if (!isEqual(this.options, Loader.instance.options)) {\n throw new Error(\n `Loader must not be called again with different options. ${JSON.stringify(\n this.options\n )} !== ${JSON.stringify(Loader.instance.options)}`\n );\n }\n\n return Loader.instance;\n }\n\n Loader.instance = this;\n }\n\n get options(): LoaderOptions {\n return {\n version: this.version,\n apiKey: this.apiKey,\n channel: this.channel,\n client: this.client,\n id: this.id,\n libraries: this.libraries,\n language: this.language,\n region: this.region,\n mapIds: this.mapIds,\n nonce: this.nonce,\n url: this.url,\n };\n }\n\n /**\n * CreateUrl returns the Google Maps JavaScript API script url given the [[LoaderOptions]].\n *\n * @ignore\n */\n createUrl(): string {\n let url = this.url;\n\n url += `?callback=${this.CALLBACK}`;\n\n if (this.apiKey) {\n url += `&key=${this.apiKey}`;\n }\n\n if (this.channel) {\n url += `&channel=${this.channel}`;\n }\n\n if (this.client) {\n url += `&client=${this.client}`;\n }\n\n if (this.libraries.length > 0) {\n url += `&libraries=${this.libraries.join(\",\")}`;\n }\n\n if (this.language) {\n url += `&language=${this.language}`;\n }\n\n if (this.region) {\n url += `®ion=${this.region}`;\n }\n\n if (this.version) {\n url += `&v=${this.version}`;\n }\n\n if (this.mapIds) {\n url += `&map_ids=${this.mapIds.join(\",\")}`;\n }\n\n return url;\n }\n\n /**\n * Load the Google Maps JavaScript API script and return a Promise.\n */\n load(): Promise {\n return this.loadPromise();\n }\n\n /**\n * Load the Google Maps JavaScript API script and return a Promise.\n *\n * @ignore\n */\n loadPromise(): Promise {\n return new Promise((resolve, reject) => {\n this.loadCallback((err: Event) => {\n if (!err) {\n resolve();\n } else {\n reject(err);\n }\n });\n });\n }\n\n /**\n * Load the Google Maps JavaScript API script with a callback.\n */\n loadCallback(fn: (e: Event) => void): void {\n this.callbacks.push(fn);\n this.execute();\n }\n\n /**\n * Set the script on document.\n */\n private setScript(): void {\n if (document.getElementById(this.id)) {\n // TODO wrap onerror callback for cases where the script was loaded elsewhere\n this.callback();\n return;\n }\n\n const url = this.createUrl();\n const script = document.createElement(\"script\");\n script.id = this.id;\n script.type = \"text/javascript\";\n script.src = url;\n script.onerror = this.loadErrorCallback.bind(this);\n script.defer = true;\n script.async = true;\n\n if (this.nonce) {\n script.nonce = this.nonce;\n }\n\n document.head.appendChild(script);\n }\n\n deleteScript(): void {\n const script = document.getElementById(this.id);\n if (script) {\n script.remove();\n }\n }\n\n private resetIfRetryingFailed(): void {\n const possibleAttempts = this.retries + 1;\n if (this.done && !this.loading && this.errors.length >= possibleAttempts) {\n this.deleteScript();\n this.done = false;\n this.loading = false;\n this.errors = [];\n }\n }\n\n private loadErrorCallback(e: ErrorEvent): void {\n this.errors.push(e);\n\n if (this.errors.length <= this.retries) {\n const delay = this.errors.length * 2 ** this.errors.length;\n\n console.log(\n `Failed to load Google Maps script, retrying in ${delay} ms.`\n );\n\n setTimeout(() => {\n this.deleteScript();\n this.setScript();\n }, delay);\n } else {\n this.onerrorEvent = e;\n this.callback();\n }\n }\n\n private setCallback(): void {\n window.__googleMapsCallback = this.callback.bind(this);\n }\n\n private callback(): void {\n this.done = true;\n this.loading = false;\n\n this.callbacks.forEach((cb) => {\n cb(this.onerrorEvent);\n });\n\n this.callbacks = [];\n }\n\n private execute(): void {\n if (window.google && window.google.maps && window.google.maps.version) {\n console.warn(\n \"Aborted attempt to load Google Maps JS with @googlemaps/js-api-loader.\" +\n \"This may result in undesirable behavior as script parameters may not match.\"\n );\n this.callback();\n }\n\n this.resetIfRetryingFailed();\n if (this.done) {\n this.callback();\n } else {\n if (this.loading) {\n // do nothing but wait\n } else {\n this.loading = true;\n this.setCallback();\n this.setScript();\n }\n }\n }\n}\n","import React, { Component } from 'react';\n\nconst style = {\n width: '100%',\n height: '100%',\n left: 0,\n top: 0,\n margin: 0,\n padding: 0,\n position: 'absolute',\n};\n\nexport default class GoogleMapMap extends Component {\n shouldComponentUpdate() {\n return false; // disable react on this div\n }\n\n render() {\n const { registerChild } = this.props;\n return
;\n }\n}\n","import EventEmitter from 'eventemitter3';\n\nexport default class MarkerDispatcher extends EventEmitter {\n constructor(gmapInstance) {\n super();\n this.gmapInstance = gmapInstance;\n }\n\n getChildren() {\n return this.gmapInstance.props.children;\n }\n\n getMousePosition() {\n return this.gmapInstance.mouse_;\n }\n\n getUpdateCounter() {\n return this.gmapInstance.updateCounter_;\n }\n\n dispose() {\n this.gmapInstance = null;\n this.removeAllListeners();\n }\n}\n","// https://github.com/acdlite/recompose/blob/master/src/packages/recompose/utils/omit.js\nconst omit = (obj, keys) => {\n const { ...rest } = obj;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n if (key in rest) {\n delete rest[key];\n }\n }\n return rest;\n};\n\nexport default omit;\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @providesModule shallowEqual\n * @typechecks\n * @flow\n */\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\n\n/**\n * inlined Object.is polyfill to avoid requiring consumers ship their own\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n */\nfunction is(x, y) {\n // SameValue algorithm\n if (x === y) {\n // Steps 1-5, 7-10\n // Steps 6.b-6.e: +0 != -0\n // Added the nonzero y check to make Flow happy, but it is redundant\n return x !== 0 || y !== 0 || 1 / x === 1 / y;\n }\n // Step 6.a: NaN == NaN\n // eslint-disable-next-line no-self-compare\n return x !== x && y !== y;\n}\n\n/**\n * Performs equality by iterating through keys on an object and returning false\n * when any key has values which are not strictly equal between the arguments.\n * Returns true when the values of all keys are strictly equal.\n */\nfunction shallowEqual(objA, objB) {\n if (is(objA, objB)) {\n return true;\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false;\n }\n\n const keysA = Object.keys(objA);\n const keysB = Object.keys(objB);\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n // Test for A's keys different from B.\n for (let i = 0; i < keysA.length; i++) {\n if (\n !hasOwnProperty.call(objB, keysA[i]) ||\n !is(objA[keysA[i]], objB[keysA[i]])\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport default shallowEqual;\n/* src: https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/shallowEqual.js */\n","import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n// utils\nimport omit from './utils/omit';\nimport shallowEqual from './utils/shallowEqual';\n\nconst mainStyle = {\n width: '100%',\n height: '100%',\n left: 0,\n top: 0,\n margin: 0,\n padding: 0,\n position: 'absolute',\n};\n\nconst style = {\n width: 0,\n height: 0,\n left: 0,\n top: 0,\n backgroundColor: 'transparent',\n position: 'absolute',\n};\n\nexport default class GoogleMapMarkers extends Component {\n /* eslint-disable react/forbid-prop-types */\n static propTypes = {\n geoService: PropTypes.any,\n style: PropTypes.any,\n distanceToMouse: PropTypes.func,\n dispatcher: PropTypes.any,\n onChildClick: PropTypes.func,\n onChildMouseDown: PropTypes.func,\n onChildMouseLeave: PropTypes.func,\n onChildMouseEnter: PropTypes.func,\n getHoverDistance: PropTypes.func,\n insideMapPanes: PropTypes.bool,\n prerender: PropTypes.bool,\n };\n /* eslint-enable react/forbid-prop-types */\n\n static defaultProps = {\n insideMapPanes: false,\n prerender: false,\n };\n\n constructor(props) {\n super(props);\n\n this.dimensionsCache_ = {};\n this.hoverKey_ = null;\n this.hoverChildProps_ = null;\n this.allowMouse_ = true;\n\n this.state = { ...this._getState(), hoverKey: null };\n }\n\n componentDidMount() {\n this.props.dispatcher.on('kON_CHANGE', this._onChangeHandler);\n this.props.dispatcher.on(\n 'kON_MOUSE_POSITION_CHANGE',\n this._onMouseChangeHandler\n );\n this.props.dispatcher.on('kON_CLICK', this._onChildClick);\n this.props.dispatcher.on('kON_MDOWN', this._onChildMouseDown);\n }\n\n shouldComponentUpdate(nextProps, nextState) {\n if (this.props.experimental === true) {\n return (\n !shallowEqual(this.props, nextProps) ||\n !shallowEqual(\n omit(this.state, ['hoverKey']),\n omit(nextState, ['hoverKey'])\n )\n );\n }\n\n return (\n !shallowEqual(this.props, nextProps) ||\n !shallowEqual(this.state, nextState)\n );\n }\n\n componentWillUnmount() {\n this.props.dispatcher.removeListener('kON_CHANGE', this._onChangeHandler);\n this.props.dispatcher.removeListener(\n 'kON_MOUSE_POSITION_CHANGE',\n this._onMouseChangeHandler\n );\n this.props.dispatcher.removeListener('kON_CLICK', this._onChildClick);\n this.props.dispatcher.removeListener('kON_MDOWN', this._onChildMouseDown);\n\n this.dimensionsCache_ = null;\n }\n\n _getState = () => ({\n children: this.props.dispatcher.getChildren(),\n updateCounter: this.props.dispatcher.getUpdateCounter(),\n });\n\n _onChangeHandler = () => {\n if (!this.dimensionsCache_) {\n return;\n }\n\n const prevChildCount = (this.state.children || []).length;\n const state = this._getState();\n\n this.setState(\n state,\n () =>\n (state.children || []).length !== prevChildCount &&\n this._onMouseChangeHandler()\n );\n };\n\n _onChildClick = () => {\n if (this.props.onChildClick) {\n if (this.hoverChildProps_) {\n const hoverKey = this.hoverKey_;\n const childProps = this.hoverChildProps_;\n // click works only on hovered item\n this.props.onChildClick(hoverKey, childProps);\n }\n }\n };\n\n _onChildMouseDown = () => {\n if (this.props.onChildMouseDown) {\n if (this.hoverChildProps_) {\n const hoverKey = this.hoverKey_;\n const childProps = this.hoverChildProps_;\n // works only on hovered item\n this.props.onChildMouseDown(hoverKey, childProps);\n }\n }\n };\n\n _onChildMouseEnter = (hoverKey, childProps) => {\n if (!this.dimensionsCache_) {\n return;\n }\n\n if (this.props.onChildMouseEnter) {\n this.props.onChildMouseEnter(hoverKey, childProps);\n }\n\n this.hoverChildProps_ = childProps;\n this.hoverKey_ = hoverKey;\n this.setState({ hoverKey });\n };\n\n _onChildMouseLeave = () => {\n if (!this.dimensionsCache_) {\n return;\n }\n\n const hoverKey = this.hoverKey_;\n const childProps = this.hoverChildProps_;\n\n if (hoverKey !== undefined && hoverKey !== null) {\n if (this.props.onChildMouseLeave) {\n this.props.onChildMouseLeave(hoverKey, childProps);\n }\n\n this.hoverKey_ = null;\n this.hoverChildProps_ = null;\n this.setState({ hoverKey: null });\n }\n };\n\n _onMouseAllow = (value) => {\n if (!value) {\n this._onChildMouseLeave();\n }\n\n this.allowMouse_ = value;\n };\n\n _onMouseChangeHandler = () => {\n if (this.allowMouse_) {\n this._onMouseChangeHandlerRaf();\n }\n };\n\n _onMouseChangeHandlerRaf = () => {\n if (!this.dimensionsCache_) {\n return;\n }\n\n const mp = this.props.dispatcher.getMousePosition();\n\n if (mp) {\n const distances = [];\n const hoverDistance = this.props.getHoverDistance();\n\n React.Children.forEach(this.state.children, (child, childIndex) => {\n if (!child) return;\n // layers\n if (\n child.props.latLng === undefined &&\n child.props.lat === undefined &&\n child.props.lng === undefined\n ) {\n return;\n }\n\n const childKey =\n child.key !== undefined && child.key !== null\n ? child.key\n : childIndex;\n const dist = this.props.distanceToMouse(\n this.dimensionsCache_[childKey],\n mp,\n child.props\n );\n if (dist < hoverDistance) {\n distances.push({\n key: childKey,\n dist,\n props: child.props,\n });\n }\n });\n\n if (distances.length) {\n distances.sort((a, b) => a.dist - b.dist);\n const hoverKey = distances[0].key;\n const childProps = distances[0].props;\n\n if (this.hoverKey_ !== hoverKey) {\n this._onChildMouseLeave();\n\n this._onChildMouseEnter(hoverKey, childProps);\n }\n } else {\n this._onChildMouseLeave();\n }\n } else {\n this._onChildMouseLeave();\n }\n };\n\n _getDimensions = (key) => {\n const childKey = key;\n return this.dimensionsCache_[childKey];\n };\n\n render() {\n const mainElementStyle = this.props.style || mainStyle;\n this.dimensionsCache_ = {};\n\n const markers = React.Children.map(\n this.state.children,\n (child, childIndex) => {\n if (!child) return undefined;\n if (\n child.props.latLng === undefined &&\n child.props.lat === undefined &&\n child.props.lng === undefined\n ) {\n return React.cloneElement(child, {\n $geoService: this.props.geoService,\n $onMouseAllow: this._onMouseAllow,\n $prerender: this.props.prerender,\n });\n }\n\n const latLng =\n child.props.latLng !== undefined\n ? child.props.latLng\n : { lat: child.props.lat, lng: child.props.lng };\n\n const pt = this.props.insideMapPanes\n ? this.props.geoService.fromLatLngToDivPixel(latLng)\n : this.props.geoService.fromLatLngToCenterPixel(latLng);\n\n const stylePtPos = {\n left: pt.x,\n top: pt.y,\n };\n\n // If the component has a southeast corner defined (either as a LatLng, or a separate\n // lat and lng pair), set the width and height based on the distance between the northwest\n // and the southeast corner to lock the overlay to the correct geographic bounds.\n if (\n child.props.seLatLng !== undefined ||\n (child.props.seLat !== undefined && child.props.seLng !== undefined)\n ) {\n const seLatLng =\n child.props.seLatLng !== undefined\n ? child.props.seLatLng\n : { lat: child.props.seLat, lng: child.props.seLng };\n\n const sePt = this.props.insideMapPanes\n ? this.props.geoService.fromLatLngToDivPixel(seLatLng)\n : this.props.geoService.fromLatLngToCenterPixel(seLatLng);\n\n stylePtPos.width = sePt.x - pt.x;\n stylePtPos.height = sePt.y - pt.y;\n }\n\n const containerPt = this.props.geoService.fromLatLngToContainerPixel(\n latLng\n );\n\n // to prevent rerender on child element i need to pass\n // const params $getDimensions and $dimensionKey instead of dimension object\n const childKey =\n child.key !== undefined && child.key !== null\n ? child.key\n : childIndex;\n\n this.dimensionsCache_[childKey] = {\n x: containerPt.x,\n y: containerPt.y,\n ...latLng,\n };\n\n return (\n \n {React.cloneElement(child, {\n $hover: childKey === this.state.hoverKey,\n $getDimensions: this._getDimensions,\n $dimensionKey: childKey,\n $geoService: this.props.geoService,\n $onMouseAllow: this._onMouseAllow,\n $prerender: this.props.prerender,\n })}\n
\n );\n }\n );\n\n return {markers}
;\n }\n}\n","import React from 'react';\nimport GoogleMapMarkers from './google_map_markers';\n\nconst style = {\n width: '50%',\n height: '50%',\n left: '50%',\n top: '50%',\n // backgroundColor: 'red',\n margin: 0,\n padding: 0,\n position: 'absolute',\n // opacity: 0.3\n};\n\nexport default function (props) {\n return (\n \n \n
\n );\n}\n","import { Loader } from '@googlemaps/js-api-loader';\n\nlet loader_;\nlet loadPromise_;\nlet resolveCustomPromise_;\n\nconst _customPromise = new Promise((resolve) => {\n resolveCustomPromise_ = resolve;\n});\n\n// TODO add libraries language and other map options\nexport default (bootstrapURLKeys, heatmapLibrary) => {\n // call from outside google-map-react\n // will be as soon as loadPromise resolved\n if (!bootstrapURLKeys) {\n return _customPromise;\n }\n\n // avoid api to be loaded multiple times\n if (loadPromise_) {\n return loadPromise_;\n }\n\n if (!bootstrapURLKeys.libraries) {\n bootstrapURLKeys.libraries = [];\n }\n\n const libraries = [...bootstrapURLKeys.libraries];\n\n // note: heatmapLibrary will be deprecated on next major\n if (heatmapLibrary) {\n // if heatmapLibrary is present\n // check if we need to add visualization library\n if (libraries.length === 0 || !libraries.includes('visualization')) {\n // if the array isEmpty or visualization is\n // not present, push the visualization library\n libraries.push('visualization');\n }\n console.warn(\n \"heatmapLibrary will be deprecated in the future. Please use { libraries: ['visualization'] } in bootstrapURLKeys property instead\"\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (Object.keys(bootstrapURLKeys).indexOf('callback') > -1) {\n const message = `\"callback\" key in bootstrapURLKeys is not allowed,\n use onGoogleApiLoaded property instead`;\n // eslint-disable-next-line no-console\n console.error(message);\n throw new Error(message);\n }\n }\n\n if (typeof window === 'undefined') {\n throw new Error('google map cannot be loaded outside browser env');\n }\n\n const { key, ...restKeys } = bootstrapURLKeys;\n\n // use single instance of Loader to avoid multiple api loads\n if (!loader_) {\n loader_ = new Loader({\n // need to keep key as a prop for backwards compatibility\n apiKey: key || '',\n ...restKeys,\n libraries,\n });\n }\n\n loadPromise_ = loader_.load().then(() => {\n resolveCustomPromise_(window.google.maps);\n return window.google.maps;\n });\n\n resolveCustomPromise_(loadPromise_);\n\n return loadPromise_;\n};\n","/* eslint-disable import/prefer-default-export */\n\nexport function wrap(n, min, max) {\n const d = max - min;\n return n === max ? n : ((((n - min) % d) + d) % d) + min;\n}\n","import { wrap } from './wrap';\n\nexport default class LatLng {\n static convert = (a) => {\n if (a instanceof LatLng) {\n return a;\n }\n\n if (Array.isArray(a)) {\n return new LatLng(a[0], a[1]);\n }\n\n if ('lng' in a && 'lat' in a) {\n return new LatLng(a.lat, a.lng);\n }\n\n return a;\n };\n\n constructor(lat, lng) {\n if (isNaN(lat) || isNaN(lng)) {\n throw new Error(`Invalid LatLng object: (${lat}, ${lng})`);\n }\n this.lat = +lat;\n this.lng = +lng;\n }\n\n wrap() {\n return new LatLng(this.lat, wrap(this.lng, -180, 180));\n }\n}\n","/* eslint-disable class-methods-use-this */\nimport Point from '@mapbox/point-geometry';\nimport LatLng from './lat_lng';\nimport { wrap } from './wrap';\n\n// A single transform, generally used for a single tile to be scaled, rotated, and zoomed.\nexport default class Transform {\n constructor(tileSize, minZoom, maxZoom) {\n this.tileSize = tileSize || 512; // constant\n\n this._minZoom = minZoom || 0;\n this._maxZoom = maxZoom || 52;\n\n this.latRange = [-85.05113, 85.05113];\n\n this.width = 0;\n this.height = 0;\n this.zoom = 0;\n this.center = new LatLng(0, 0);\n this.angle = 0;\n }\n\n get minZoom() {\n return this._minZoom;\n }\n\n set minZoom(zoom) {\n this._minZoom = zoom;\n this.zoom = Math.max(this.zoom, zoom);\n }\n\n get maxZoom() {\n return this._maxZoom;\n }\n\n set maxZoom(zoom) {\n this._maxZoom = zoom;\n this.zoom = Math.min(this.zoom, zoom);\n }\n\n get worldSize() {\n return this.tileSize * this.scale;\n }\n\n get centerPoint() {\n return new Point(0, 0); // this.size._div(2);\n }\n\n get size() {\n return new Point(this.width, this.height);\n }\n\n get bearing() {\n return (-this.angle / Math.PI) * 180;\n }\n\n set bearing(bearing) {\n this.angle = (-wrap(bearing, -180, 180) * Math.PI) / 180;\n }\n\n get zoom() {\n return this._zoom;\n }\n\n set zoom(zoom) {\n const zoomV = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);\n this._zoom = zoomV;\n this.scale = this.zoomScale(zoomV);\n this.tileZoom = Math.floor(zoomV);\n this.zoomFraction = zoomV - this.tileZoom;\n }\n\n zoomScale(zoom) {\n return Math.pow(2, zoom);\n }\n\n scaleZoom(scale) {\n return Math.log(scale) / Math.LN2;\n }\n\n project(latlng, worldSize) {\n return new Point(\n this.lngX(latlng.lng, worldSize),\n this.latY(latlng.lat, worldSize)\n );\n }\n\n unproject(point, worldSize) {\n return new LatLng(\n this.yLat(point.y, worldSize),\n this.xLng(point.x, worldSize)\n );\n }\n\n get x() {\n return this.lngX(this.center.lng);\n }\n\n get y() {\n return this.latY(this.center.lat);\n }\n\n get point() {\n return new Point(this.x, this.y);\n }\n\n // lat/lon <-> absolute pixel coords convertion\n lngX(lon, worldSize) {\n return ((180 + lon) * (worldSize || this.worldSize)) / 360;\n }\n\n // latitude to absolute y coord\n latY(lat, worldSize) {\n const y =\n (180 / Math.PI) * Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360));\n return ((180 - y) * (worldSize || this.worldSize)) / 360;\n }\n\n xLng(x, worldSize) {\n return (x * 360) / (worldSize || this.worldSize) - 180;\n }\n\n yLat(y, worldSize) {\n const y2 = 180 - (y * 360) / (worldSize || this.worldSize);\n return (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;\n }\n\n locationPoint(latlng) {\n const p = this.project(latlng);\n return this.centerPoint._sub(this.point._sub(p)._rotate(this.angle));\n }\n\n pointLocation(p) {\n const p2 = this.centerPoint._sub(p)._rotate(-this.angle);\n return this.unproject(this.point.sub(p2));\n }\n}\n","import Point from '@mapbox/point-geometry';\n\nimport LatLng from './lat_lng';\nimport Transform from './transform';\n\nexport default class Geo {\n constructor(tileSize) {\n // left_top view пользует гугл\n // super();\n this.hasSize_ = false;\n this.hasView_ = false;\n this.transform_ = new Transform(tileSize || 512);\n }\n\n setView(center, zoom, bearing) {\n this.transform_.center = LatLng.convert(center);\n this.transform_.zoom = +zoom;\n this.transform_.bearing = +bearing;\n this.hasView_ = true;\n }\n\n setViewSize(width, height) {\n this.transform_.width = width;\n this.transform_.height = height;\n this.hasSize_ = true;\n }\n\n setMapCanvasProjection(maps, mapCanvasProjection) {\n this.maps_ = maps;\n this.mapCanvasProjection_ = mapCanvasProjection;\n }\n\n canProject() {\n return this.hasSize_ && this.hasView_;\n }\n\n hasSize() {\n return this.hasSize_;\n }\n\n /** Returns the pixel position relative to the map center. */\n fromLatLngToCenterPixel(ptLatLng) {\n return this.transform_.locationPoint(LatLng.convert(ptLatLng));\n }\n\n /**\n * Returns the pixel position relative to the map panes,\n * or relative to the map center if there are no panes.\n */\n fromLatLngToDivPixel(ptLatLng) {\n if (this.mapCanvasProjection_) {\n const latLng = new this.maps_.LatLng(ptLatLng.lat, ptLatLng.lng);\n return this.mapCanvasProjection_.fromLatLngToDivPixel(latLng);\n }\n return this.fromLatLngToCenterPixel(ptLatLng);\n }\n\n /** Returns the pixel position relative to the map top-left. */\n fromLatLngToContainerPixel(ptLatLng) {\n if (this.mapCanvasProjection_) {\n const latLng = new this.maps_.LatLng(ptLatLng.lat, ptLatLng.lng);\n return this.mapCanvasProjection_.fromLatLngToContainerPixel(latLng);\n }\n\n const pt = this.fromLatLngToCenterPixel(ptLatLng);\n pt.x -=\n this.transform_.worldSize * Math.round(pt.x / this.transform_.worldSize);\n\n pt.x += this.transform_.width / 2;\n pt.y += this.transform_.height / 2;\n\n return pt;\n }\n\n /** Returns the LatLng for the given offset from the map top-left. */\n fromContainerPixelToLatLng(ptXY) {\n if (this.mapCanvasProjection_) {\n const latLng = this.mapCanvasProjection_.fromContainerPixelToLatLng(ptXY);\n return { lat: latLng.lat(), lng: latLng.lng() };\n }\n\n const ptxy = { ...ptXY };\n ptxy.x -= this.transform_.width / 2;\n ptxy.y -= this.transform_.height / 2;\n const ptRes = this.transform_.pointLocation(Point.convert(ptxy));\n\n ptRes.lng -= 360 * Math.round(ptRes.lng / 360); // convert 2 google format\n return ptRes;\n }\n\n getWidth() {\n return this.transform_.width;\n }\n\n getHeight() {\n return this.transform_.height;\n }\n\n getZoom() {\n return this.transform_.zoom;\n }\n\n getCenter() {\n const ptRes = this.transform_.pointLocation({ x: 0, y: 0 });\n\n return ptRes;\n }\n\n getBounds(margins, roundFactor) {\n const bndT = (margins && margins[0]) || 0;\n const bndR = (margins && margins[1]) || 0;\n const bndB = (margins && margins[2]) || 0;\n const bndL = (margins && margins[3]) || 0;\n\n if (\n this.getWidth() - bndR - bndL > 0 &&\n this.getHeight() - bndT - bndB > 0\n ) {\n const topLeftCorner = this.transform_.pointLocation(\n Point.convert({\n x: bndL - this.getWidth() / 2,\n y: bndT - this.getHeight() / 2,\n })\n );\n const bottomRightCorner = this.transform_.pointLocation(\n Point.convert({\n x: this.getWidth() / 2 - bndR,\n y: this.getHeight() / 2 - bndB,\n })\n );\n\n let res = [\n topLeftCorner.lat,\n topLeftCorner.lng, // NW\n bottomRightCorner.lat,\n bottomRightCorner.lng, // SE\n bottomRightCorner.lat,\n topLeftCorner.lng, // SW\n topLeftCorner.lat,\n bottomRightCorner.lng, // NE\n ];\n\n if (roundFactor) {\n res = res.map((r) => Math.round(r * roundFactor) / roundFactor);\n }\n return res;\n }\n\n return [0, 0, 0, 0];\n }\n}\n","export default function raf(callback) {\n if (window.requestAnimationFrame) {\n return window.requestAnimationFrame(callback);\n }\n\n const nativeRaf =\n window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;\n\n return nativeRaf\n ? nativeRaf(callback)\n : window.setTimeout(callback, 1e3 / 60);\n}\n","const log2 = Math.log2 ? Math.log2 : (x) => Math.log(x) / Math.LN2;\n\nexport default log2;\n","// source taken from https://github.com/rackt/redux/blob/master/src/utils/pick.js\n\nexport default function pick(obj, fn) {\n return Object.keys(obj).reduce((result, key) => {\n if (fn(obj[key])) {\n result[key] = obj[key]; // eslint-disable-line\n }\n return result;\n }, {});\n}\n","const isEmpty = (val) => {\n // check for empty object {}, array []\n if (val !== null && typeof val === 'object') {\n if (Object.keys(val).length === 0) {\n return true;\n }\n } else if (val === null || val === undefined || val === '') {\n // check for undefined, null and \"\"\n return true;\n }\n return false;\n};\n\nexport default isEmpty;\n","function isObjectLike(value) {\n return !!value && typeof value === 'object';\n}\n\nconst objectToString = Object.prototype.toString;\n\nexport default function isNumber(value) {\n const numberTag = '[object Number]';\n return (\n typeof value === 'number' ||\n (isObjectLike(value) && objectToString.call(value) === numberTag)\n );\n}\n","// http://stackoverflow.com/questions/5899783/detect-safari-chrome-ie-firefox-opera-with-user-agent\nlet detectBrowserResult_ = null;\n\nexport default function detectBrowser() {\n if (detectBrowserResult_) {\n return detectBrowserResult_;\n }\n\n if (typeof navigator !== 'undefined') {\n const isExplorer = navigator.userAgent.indexOf('MSIE') > -1;\n const isFirefox = navigator.userAgent.indexOf('Firefox') > -1;\n const isOpera = navigator.userAgent.toLowerCase().indexOf('op') > -1;\n\n let isChrome = navigator.userAgent.indexOf('Chrome') > -1;\n let isSafari = navigator.userAgent.indexOf('Safari') > -1;\n\n if (isChrome && isSafari) {\n isSafari = false;\n }\n\n if (isChrome && isOpera) {\n isChrome = false;\n }\n\n detectBrowserResult_ = {\n isExplorer,\n isFirefox,\n isOpera,\n isChrome,\n isSafari,\n };\n return detectBrowserResult_;\n }\n\n detectBrowserResult_ = {\n isChrome: true,\n isExplorer: false,\n isFirefox: false,\n isOpera: false,\n isSafari: false,\n };\n\n return detectBrowserResult_;\n}\n","// source taken from https://github.com/rackt/redux/blob/master/src/utils/isPlainObject.js\nconst fnToString = (fn) => Function.prototype.toString.call(fn);\n\n/**\n * @param {any} obj The object to inspect.\n * @returns {boolean} True if the argument appears to be a plain object.\n */\nexport default function isPlainObject(obj) {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n\n const proto =\n typeof obj.constructor === 'function'\n ? Object.getPrototypeOf(obj)\n : Object.prototype;\n\n if (proto === null) {\n return true;\n }\n\n const constructor = proto.constructor;\n\n return (\n typeof constructor === 'function' &&\n constructor instanceof constructor &&\n fnToString(constructor) === fnToString(Object)\n );\n}\n","// feature detection for passive support\n// see: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support\nfunction hasPassiveSupport() {\n let passiveSupported = false;\n\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n passiveSupported = true;\n },\n });\n\n window.addEventListener('test', options, options);\n window.removeEventListener('test', options, options);\n } catch (err) {\n passiveSupported = false;\n }\n\n return passiveSupported;\n}\n\nexport default function addPassiveEventListener(\n element,\n eventName,\n func,\n capture\n) {\n element.addEventListener(\n eventName,\n func,\n hasPassiveSupport()\n ? {\n capture,\n passive: true,\n }\n : capture\n );\n}\n","/* eslint-disable */\n/**\n* Detect Element Resize.\n* Forked in order to guard against unsafe 'window' and 'document' references.\n*\n* https://github.com/sdecima/javascript-detect-element-resize\n* Sebastian Decima\n*\n* version: 0.5.3\n**/\n\nimport addPassiveEventListener from './passiveEvents';\n\n// Reliable `window` and `document` detection\nvar canUseDOM = !!(typeof window !== 'undefined' &&\n window.document &&\n window.document.createElement);\n\n// Check `document` and `window` in case of server-side rendering\nvar _window;\nif (canUseDOM) {\n _window = window;\n} else if (typeof self !== 'undefined') {\n _window = self;\n} else {\n _window = this;\n}\n\nvar attachEvent = typeof document !== 'undefined' && document.attachEvent;\nvar stylesCreated = false;\n\nif (canUseDOM && !attachEvent) {\n var requestFrame = (function () {\n var raf = _window.requestAnimationFrame ||\n _window.mozRequestAnimationFrame ||\n _window.webkitRequestAnimationFrame ||\n function (fn) {\n return _window.setTimeout(fn, 20);\n };\n return function (fn) {\n return raf(fn);\n };\n })();\n\n var cancelFrame = (function () {\n var cancel = _window.cancelAnimationFrame ||\n _window.mozCancelAnimationFrame ||\n _window.webkitCancelAnimationFrame ||\n _window.clearTimeout;\n return function (id) {\n return cancel(id);\n };\n })();\n\n var resetTriggers = function (element) {\n var triggers = element.__resizeTriggers__,\n expand = triggers.firstElementChild,\n contract = triggers.lastElementChild,\n expandChild = expand.firstElementChild;\n contract.scrollLeft = contract.scrollWidth;\n contract.scrollTop = contract.scrollHeight;\n expandChild.style.width = expand.offsetWidth + 1 + 'px';\n expandChild.style.height = expand.offsetHeight + 1 + 'px';\n expand.scrollLeft = expand.scrollWidth;\n expand.scrollTop = expand.scrollHeight;\n };\n\n var checkTriggers = function (element) {\n return element.offsetWidth != element.__resizeLast__.width ||\n element.offsetHeight != element.__resizeLast__.height;\n };\n\n var scrollListener = function (e) {\n var element = this;\n resetTriggers(this);\n if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);\n this.__resizeRAF__ = requestFrame(function () {\n if (checkTriggers(element)) {\n element.__resizeLast__.width = element.offsetWidth;\n element.__resizeLast__.height = element.offsetHeight;\n element.__resizeListeners__.forEach(function (fn) {\n fn.call(element, e);\n });\n }\n });\n };\n\n /* Detect CSS Animations support to detect element display/re-attach */\n var animation = false,\n animationstring = 'animation',\n keyframeprefix = '',\n animationstartevent = 'animationstart',\n domPrefixes = 'Webkit Moz O ms'.split(' '),\n startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(\n ' '\n ),\n pfx = '';\n\n if (canUseDOM) {\n var elm = document.createElement('fakeelement');\n if (elm.style.animationName !== undefined) {\n animation = true;\n }\n\n if (animation === false) {\n for (var i = 0; i < domPrefixes.length; i++) {\n if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {\n pfx = domPrefixes[i];\n animationstring = pfx + 'Animation';\n keyframeprefix = '-' + pfx.toLowerCase() + '-';\n animationstartevent = startEvents[i];\n animation = true;\n break;\n }\n }\n }\n }\n\n var animationName = 'resizeanim';\n var animationKeyframes = '@' +\n keyframeprefix +\n 'keyframes ' +\n animationName +\n ' { from { opacity: 0; } to { opacity: 0; } } ';\n var animationStyle = keyframeprefix +\n 'animation: 1ms ' +\n animationName +\n '; ';\n}\n\nvar createStyles = function () {\n if (!stylesCreated) {\n //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360\n var css = (animationKeyframes ? animationKeyframes : '') +\n '.resize-triggers { ' +\n (animationStyle ? animationStyle : '') +\n 'visibility: hidden; opacity: 0; } ' +\n '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',\n head = document.head || document.getElementsByTagName('head')[0],\n style = document.createElement('style');\n\n style.type = 'text/css';\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n\n head.appendChild(style);\n stylesCreated = true;\n }\n};\n\nvar addResizeListener = function (element, fn) {\n if (element.parentNode === undefined) {\n var tempParentDiv = document.createElement('div');\n element.parentNode = tempParentDiv;\n }\n element = element.parentNode;\n if (attachEvent)\n element.attachEvent('onresize', fn);\n else {\n if (!element.__resizeTriggers__) {\n if (getComputedStyle(element).position == 'static')\n element.style.position = 'relative';\n createStyles();\n element.__resizeLast__ = {};\n element.__resizeListeners__ = [];\n (element.__resizeTriggers__ = document.createElement(\n 'div'\n )).className = 'resize-triggers';\n element.__resizeTriggers__.innerHTML = '' +\n '
';\n element.appendChild(element.__resizeTriggers__);\n resetTriggers(element);\n\n addPassiveEventListener(element, 'scroll', scrollListener, true);\n\n /* Listen for a css animation to detect element display/re-attach */\n animationstartevent &&\n element.__resizeTriggers__.addEventListener(\n animationstartevent,\n function (e) {\n if (e.animationName == animationName) resetTriggers(element);\n }\n );\n }\n element.__resizeListeners__.push(fn);\n }\n};\n\nvar removeResizeListener = function (element, fn) {\n element = element.parentNode;\n if (attachEvent)\n element.detachEvent('onresize', fn);\n else {\n element.__resizeListeners__.splice(\n element.__resizeListeners__.indexOf(fn),\n 1\n );\n if (!element.__resizeListeners__.length) {\n element.removeEventListener('scroll', scrollListener);\n element.__resizeTriggers__ = !element.removeChild(\n element.__resizeTriggers__\n );\n }\n }\n};\n\nexport {\n addResizeListener,\n removeResizeListener,\n};\n","/* eslint-disable import/no-extraneous-dependencies, react/forbid-prop-types, react/no-find-dom-node, no-console, no-undef */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport ReactDOM from 'react-dom';\n\n// helpers\nimport GoogleMapMap from './google_map_map';\nimport MarkerDispatcher from './marker_dispatcher';\nimport GoogleMapMarkers from './google_map_markers';\nimport GoogleMapMarkersPrerender from './google_map_markers_prerender';\nimport { generateHeatmap, optionsHeatmap } from './google_heatmap';\n\n// loaders\nimport googleMapLoader from './loaders/google_map_loader';\n\n// lib\nimport Geo from './lib/geo';\n\n// tools\nimport raf from './utils/raf';\nimport log2 from './utils/log2';\nimport omit from './utils/omit';\nimport pick from './utils/pick';\nimport isEmpty from './utils/isEmpty';\nimport isNumber from './utils/isNumber';\nimport detectBrowser from './utils/detect';\nimport shallowEqual from './utils/shallowEqual';\nimport isPlainObject from './utils/isPlainObject';\nimport isArraysEqualEps from './utils/isArraysEqualEps';\nimport {\n addResizeListener,\n removeResizeListener,\n} from './utils/detectElementResize';\nimport addPassiveEventListener from './utils/passiveEvents';\n\n// consts\nconst kEPS = 0.00001;\nconst K_GOOGLE_TILE_SIZE = 256;\n// real minZoom calculated here _getMinZoom\nconst K_IDLE_TIMEOUT = 100;\nconst K_IDLE_CLICK_TIMEOUT = 300;\nconst DEFAULT_MIN_ZOOM = 3;\n// Starting with version 3.32, the maps API calls `draw()` each frame during\n// a zoom animation.\nconst DRAW_CALLED_DURING_ANIMATION_VERSION = 32;\nconst IS_REACT_16 = ReactDOM.createPortal !== undefined;\n\nconst createPortal = IS_REACT_16\n ? ReactDOM.createPortal\n : ReactDOM.unstable_renderSubtreeIntoContainer;\n\nfunction defaultOptions_(/* maps */) {\n return {\n overviewMapControl: false,\n streetViewControl: false,\n rotateControl: true,\n mapTypeControl: false,\n // disable poi\n styles: [\n {\n featureType: 'poi',\n elementType: 'labels',\n stylers: [{ visibility: 'off' }],\n },\n ],\n minZoom: DEFAULT_MIN_ZOOM, // dynamically recalculted if possible during init\n };\n}\n\nconst latLng2Obj = (latLng) =>\n isPlainObject(latLng) ? latLng : { lat: latLng[0], lng: latLng[1] };\n\nconst _checkMinZoom = (zoom, minZoom) => {\n if (process.env.NODE_ENV !== 'production') {\n if (zoom < minZoom) {\n console.warn(\n 'GoogleMap: ' + // eslint-disable-line\n 'minZoom option is less than recommended ' +\n 'minZoom option for your map sizes.\\n' +\n 'overrided to value ' +\n minZoom\n );\n }\n }\n\n if (minZoom < zoom) {\n return zoom;\n }\n return minZoom;\n};\n\nconst isFullScreen = () =>\n document.fullscreen ||\n document.webkitIsFullScreen ||\n document.mozFullScreen ||\n document.msFullscreenElement;\n\nclass GoogleMap extends Component {\n static propTypes = {\n apiKey: PropTypes.string,\n bootstrapURLKeys: PropTypes.any,\n\n defaultCenter: PropTypes.oneOfType([\n PropTypes.array,\n PropTypes.shape({\n lat: PropTypes.number,\n lng: PropTypes.number,\n }),\n ]),\n center: PropTypes.oneOfType([\n PropTypes.array,\n PropTypes.shape({\n lat: PropTypes.number,\n lng: PropTypes.number,\n }),\n ]),\n defaultZoom: PropTypes.number,\n zoom: PropTypes.number,\n onBoundsChange: PropTypes.func,\n onChange: PropTypes.func,\n onClick: PropTypes.func,\n onChildClick: PropTypes.func,\n onChildMouseDown: PropTypes.func,\n onChildMouseUp: PropTypes.func,\n onChildMouseMove: PropTypes.func,\n onChildMouseEnter: PropTypes.func,\n onChildMouseLeave: PropTypes.func,\n onZoomAnimationStart: PropTypes.func,\n onZoomAnimationEnd: PropTypes.func,\n onDrag: PropTypes.func,\n onDragEnd: PropTypes.func,\n onMapTypeIdChange: PropTypes.func,\n onTilesLoaded: PropTypes.func,\n options: PropTypes.any,\n distanceToMouse: PropTypes.func,\n hoverDistance: PropTypes.number,\n debounced: PropTypes.bool,\n margin: PropTypes.array,\n googleMapLoader: PropTypes.any,\n onGoogleApiLoaded: PropTypes.func,\n yesIWantToUseGoogleMapApiInternals: PropTypes.bool,\n draggable: PropTypes.bool,\n style: PropTypes.any,\n resetBoundsOnResize: PropTypes.bool,\n layerTypes: PropTypes.arrayOf(PropTypes.string), // ['TransitLayer', 'TrafficLayer']\n shouldUnregisterMapOnUnmount: PropTypes.bool,\n };\n\n static defaultProps = {\n distanceToMouse(pt, mousePos /* , markerProps */) {\n return Math.sqrt(\n (pt.x - mousePos.x) * (pt.x - mousePos.x) +\n (pt.y - mousePos.y) * (pt.y - mousePos.y)\n );\n },\n hoverDistance: 30,\n debounced: true,\n options: defaultOptions_,\n googleMapLoader,\n yesIWantToUseGoogleMapApiInternals: false,\n style: {\n width: '100%',\n height: '100%',\n margin: 0,\n padding: 0,\n position: 'relative',\n },\n layerTypes: [],\n heatmap: {},\n heatmapLibrary: false,\n shouldUnregisterMapOnUnmount: true,\n };\n\n static googleMapLoader = googleMapLoader; // eslint-disable-line\n\n constructor(props) {\n super(props);\n this.mounted_ = false;\n this.initialized_ = false;\n this.googleApiLoadedCalled_ = false;\n\n this.map_ = null;\n this.maps_ = null;\n this.prevBounds_ = null;\n this.heatmap = null;\n\n this.layers_ = {};\n\n this.mouse_ = null;\n this.mouseMoveTime_ = 0;\n this.boundingRect_ = null;\n this.mouseInMap_ = true;\n\n this.dragTime_ = 0;\n this.fireMouseEventOnIdle_ = false;\n this.updateCounter_ = 0;\n\n this.markersDispatcher_ = new MarkerDispatcher(this);\n this.geoService_ = new Geo(K_GOOGLE_TILE_SIZE);\n this.centerIsObject_ = isPlainObject(this.props.center);\n\n this.minZoom_ = DEFAULT_MIN_ZOOM;\n this.defaultDraggableOption_ = true;\n\n this.zoomControlClickTime_ = 0;\n\n this.childMouseDownArgs_ = null;\n this.childMouseUpTime_ = 0;\n\n this.googleMapDom_ = null;\n\n if (process.env.NODE_ENV !== 'production') {\n if (this.props.apiKey) {\n console.warn(\n 'GoogleMap: ' + // eslint-disable-line no-console\n 'apiKey is deprecated, use ' +\n 'bootstrapURLKeys={{key: YOUR_API_KEY}} instead.'\n );\n }\n\n if (this.props.onBoundsChange) {\n console.warn(\n 'GoogleMap: ' + // eslint-disable-line no-console\n 'onBoundsChange is deprecated, use ' +\n 'onChange({center, zoom, bounds, ...other}) instead.'\n );\n }\n\n if (isEmpty(this.props.center) && isEmpty(this.props.defaultCenter)) {\n console.warn(\n 'GoogleMap: center or defaultCenter property must be defined' // eslint-disable-line no-console\n );\n }\n\n if (isEmpty(this.props.zoom) && isEmpty(this.props.defaultZoom)) {\n console.warn(\n 'GoogleMap: zoom or defaultZoom property must be defined' // eslint-disable-line no-console\n );\n }\n }\n\n if (this._isCenterDefined(this.props.center || this.props.defaultCenter)) {\n const propsCenter = latLng2Obj(\n this.props.center || this.props.defaultCenter\n );\n this.geoService_.setView(\n propsCenter,\n this.props.zoom || this.props.defaultZoom,\n 0\n );\n }\n\n this.zoomAnimationInProgress_ = false;\n\n this.state = {\n overlay: null,\n };\n }\n\n componentDidMount() {\n this.mounted_ = true;\n addPassiveEventListener(window, 'resize', this._onWindowResize, false);\n addPassiveEventListener(window, 'keydown', this._onKeyDownCapture, true);\n const mapDom = ReactDOM.findDOMNode(this.googleMapDom_);\n // gmap can't prevent map drag if mousedown event already occured\n // the only workaround I find is prevent mousedown native browser event\n\n if (mapDom) {\n addPassiveEventListener(\n mapDom,\n 'mousedown',\n this._onMapMouseDownNative,\n true\n );\n }\n\n addPassiveEventListener(window, 'mouseup', this._onChildMouseUp, false);\n const bootstrapURLKeys = {\n ...(this.props.apiKey && { key: this.props.apiKey }),\n ...this.props.bootstrapURLKeys,\n };\n\n this.props.googleMapLoader(bootstrapURLKeys, this.props.heatmapLibrary); // we can start load immediatly\n\n setTimeout(\n () => {\n // to detect size\n this._setViewSize();\n if (\n this._isCenterDefined(this.props.center || this.props.defaultCenter)\n ) {\n this._initMap();\n }\n },\n 0,\n this\n );\n if (this.props.resetBoundsOnResize) {\n const that = this;\n addResizeListener(mapDom, that._mapDomResizeCallback);\n }\n }\n\n shouldComponentUpdate(nextProps, nextState) {\n // draggable does not affect inner components\n return (\n !shallowEqual(\n omit(this.props, ['draggable']),\n omit(nextProps, ['draggable'])\n ) || !shallowEqual(this.state, nextState)\n );\n }\n\n componentDidUpdate(prevProps) {\n if (process.env.NODE_ENV !== 'production') {\n if (!shallowEqual(prevProps.defaultCenter, this.props.defaultCenter)) {\n console.warn(\n \"GoogleMap: defaultCenter prop changed. You can't change default props.\"\n );\n }\n\n if (!shallowEqual(prevProps.defaultZoom, this.props.defaultZoom)) {\n console.warn(\n \"GoogleMap: defaultZoom prop changed. You can't change default props.\"\n );\n }\n }\n\n if (\n !this._isCenterDefined(prevProps.center) &&\n this._isCenterDefined(this.props.center)\n ) {\n setTimeout(() => this._initMap(), 0);\n }\n\n if (this.map_) {\n const centerLatLng = this.geoService_.getCenter();\n if (this._isCenterDefined(this.props.center)) {\n const currentCenter = latLng2Obj(this.props.center);\n const prevCenter = this._isCenterDefined(prevProps.center)\n ? latLng2Obj(prevProps.center)\n : null;\n\n if (\n !prevCenter ||\n Math.abs(currentCenter.lat - prevCenter.lat) +\n Math.abs(currentCenter.lng - prevCenter.lng) >\n kEPS\n ) {\n if (\n Math.abs(currentCenter.lat - centerLatLng.lat) +\n Math.abs(currentCenter.lng - centerLatLng.lng) >\n kEPS\n ) {\n this.map_.panTo({\n lat: currentCenter.lat,\n lng: currentCenter.lng,\n });\n }\n }\n }\n\n if (!isEmpty(this.props.zoom)) {\n // if zoom chaged by user\n if (Math.abs(this.props.zoom - prevProps.zoom) > 0) {\n this.map_.setZoom(this.props.zoom);\n }\n }\n\n if (!isEmpty(prevProps.draggable) && isEmpty(this.props.draggable)) {\n // reset to default\n this.map_.setOptions({ draggable: this.defaultDraggableOption_ });\n } else if (!shallowEqual(prevProps.draggable, this.props.draggable)) {\n // also prevent this on window 'mousedown' event to prevent map move\n this.map_.setOptions({ draggable: this.props.draggable });\n }\n\n // use shallowEqual to try avoid calling map._setOptions if only the ref changes\n if (\n !isEmpty(this.props.options) &&\n !shallowEqual(prevProps.options, this.props.options)\n ) {\n const mapPlainObjects = pick(this.maps_, isPlainObject);\n let options =\n typeof this.props.options === 'function'\n ? this.props.options(mapPlainObjects)\n : this.props.options;\n // remove zoom, center and draggable options as these are managed by google-maps-react\n options = omit(options, ['zoom', 'center', 'draggable']);\n\n if ('minZoom' in options) {\n const minZoom = this._computeMinZoom(options.minZoom);\n options.minZoom = _checkMinZoom(options.minZoom, minZoom);\n }\n\n this.map_.setOptions(options);\n }\n\n if (!shallowEqual(this.props.layerTypes, prevProps.layerTypes)) {\n Object.keys(this.layers_).forEach((layerKey) => {\n this.layers_[layerKey].setMap(null);\n delete this.layers_[layerKey];\n });\n this._setLayers(this.props.layerTypes);\n }\n\n if (\n this.heatmap &&\n !shallowEqual(this.props.heatmap.positions, prevProps.heatmap.positions)\n ) {\n this.heatmap.setData(\n this.props.heatmap.positions.map((p) => ({\n location: new this.maps_.LatLng(p.lat, p.lng),\n weight: p.weight,\n }))\n );\n }\n if (\n this.heatmap &&\n !shallowEqual(this.props.heatmap.options, prevProps.heatmap.options)\n ) {\n Object.keys(this.props.heatmap.options).forEach((option) => {\n this.heatmap.set(option, this.props.heatmap.options[option]);\n });\n }\n }\n // emit actions\n this.markersDispatcher_.emit('kON_CHANGE');\n\n if (!shallowEqual(this.props.hoverDistance, prevProps.hoverDistance)) {\n this.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE');\n }\n }\n\n componentWillUnmount() {\n this.mounted_ = false;\n const mapDom = ReactDOM.findDOMNode(this.googleMapDom_);\n if (mapDom) {\n mapDom.removeEventListener('mousedown', this._onMapMouseDownNative, true);\n }\n window.removeEventListener('resize', this._onWindowResize);\n window.removeEventListener('keydown', this._onKeyDownCapture);\n window.removeEventListener('mouseup', this._onChildMouseUp, false);\n if (this.props.resetBoundsOnResize) {\n removeResizeListener(mapDom, this._mapDomResizeCallback);\n }\n\n if (this.overlay_) {\n // this triggers overlay_.onRemove(), which will unmount the \n this.overlay_.setMap(null);\n }\n\n if (this.maps_ && this.map_ && this.props.shouldUnregisterMapOnUnmount) {\n // fix google, as otherwise listeners works even without map\n this.map_.setOptions({ scrollwheel: false });\n this.maps_.event.clearInstanceListeners(this.map_);\n }\n\n if (this.props.shouldUnregisterMapOnUnmount) {\n this.map_ = null;\n this.maps_ = null;\n }\n this.markersDispatcher_.dispose();\n\n this.resetSizeOnIdle_ = false;\n\n if (this.props.shouldUnregisterMapOnUnmount) {\n delete this.map_;\n delete this.markersDispatcher_;\n }\n }\n\n // calc minZoom if map size available\n // it's better to not set minZoom less than this calculation gives\n // otherwise there is no homeomorphism between screen coordinates and map\n // (one map coordinate can have different screen coordinates)\n _getMinZoom = () => {\n if (this.geoService_.getWidth() > 0 || this.geoService_.getHeight() > 0) {\n const tilesPerWidth =\n Math.ceil(this.geoService_.getWidth() / K_GOOGLE_TILE_SIZE) + 2;\n const tilesPerHeight =\n Math.ceil(this.geoService_.getHeight() / K_GOOGLE_TILE_SIZE) + 2;\n const maxTilesPerDim = Math.max(tilesPerWidth, tilesPerHeight);\n return Math.ceil(log2(maxTilesPerDim));\n }\n return DEFAULT_MIN_ZOOM;\n };\n\n _computeMinZoom = (minZoom) => {\n if (!isEmpty(minZoom)) {\n return minZoom;\n }\n return this._getMinZoom();\n };\n\n _mapDomResizeCallback = () => {\n this.resetSizeOnIdle_ = true;\n if (this.maps_) {\n const originalCenter = this.props.center || this.props.defaultCenter;\n const currentCenter = this.map_.getCenter();\n this.maps_.event.trigger(this.map_, 'resize');\n this.map_.setCenter(\n this.props.resetBoundsOnResize ? originalCenter : currentCenter\n );\n }\n };\n\n _setLayers = (layerTypes) => {\n layerTypes.forEach((layerType) => {\n this.layers_[layerType] = new this.maps_[layerType]();\n this.layers_[layerType].setMap(this.map_);\n });\n };\n\n _renderPortal = () => (\n \n );\n\n _initMap = () => {\n // only initialize the map once\n if (this.initialized_) {\n return;\n }\n this.initialized_ = true;\n\n const propsCenter = latLng2Obj(\n this.props.center || this.props.defaultCenter\n );\n this.geoService_.setView(\n propsCenter,\n this.props.zoom || this.props.defaultZoom,\n 0\n );\n\n this._onBoundsChanged(); // now we can calculate map bounds center etc...\n\n const bootstrapURLKeys = {\n ...(this.props.apiKey && { key: this.props.apiKey }),\n ...this.props.bootstrapURLKeys,\n };\n\n this.props\n .googleMapLoader(bootstrapURLKeys, this.props.heatmapLibrary)\n .then((maps) => {\n if (!this.mounted_) {\n return;\n }\n\n const centerLatLng = this.geoService_.getCenter();\n\n const propsOptions = {\n zoom: this.props.zoom || this.props.defaultZoom,\n center: new maps.LatLng(centerLatLng.lat, centerLatLng.lng),\n };\n\n // Start Heatmap\n if (this.props.heatmap.positions) {\n Object.assign(this, {\n heatmap: generateHeatmap(maps, this.props.heatmap),\n });\n optionsHeatmap(this.heatmap, this.props.heatmap);\n }\n // End Heatmap\n\n // prevent to exapose full api\n // next props must be exposed (console.log(Object.keys(pick(maps, isPlainObject))))\n // \"Animation\", \"ControlPosition\", \"MapTypeControlStyle\", \"MapTypeId\",\n // \"NavigationControlStyle\", \"ScaleControlStyle\", \"StrokePosition\",\n // \"SymbolPath\", \"ZoomControlStyle\",\n // \"event\", \"DirectionsStatus\", \"DirectionsTravelMode\", \"DirectionsUnitSystem\",\n // \"DistanceMatrixStatus\",\n // \"DistanceMatrixElementStatus\", \"ElevationStatus\", \"GeocoderLocationType\",\n // \"GeocoderStatus\", \"KmlLayerStatus\",\n // \"MaxZoomStatus\", \"StreetViewStatus\", \"TransitMode\", \"TransitRoutePreference\",\n // \"TravelMode\", \"UnitSystem\"\n const mapPlainObjects = pick(maps, isPlainObject);\n const options =\n typeof this.props.options === 'function'\n ? this.props.options(mapPlainObjects)\n : this.props.options;\n const defaultOptions = defaultOptions_(mapPlainObjects);\n\n const draggableOptions = !isEmpty(this.props.draggable) && {\n draggable: this.props.draggable,\n };\n\n const minZoom = this._computeMinZoom(options.minZoom);\n this.minZoom_ = minZoom;\n\n const preMapOptions = {\n ...defaultOptions,\n minZoom,\n ...options,\n ...propsOptions,\n };\n\n this.defaultDraggableOption_ = !isEmpty(preMapOptions.draggable)\n ? preMapOptions.draggable\n : this.defaultDraggableOption_;\n\n const mapOptions = {\n ...preMapOptions,\n ...draggableOptions,\n };\n\n mapOptions.minZoom = _checkMinZoom(mapOptions.minZoom, minZoom);\n\n const map = new maps.Map(\n ReactDOM.findDOMNode(this.googleMapDom_),\n mapOptions\n );\n\n this.map_ = map;\n this.maps_ = maps;\n\n this._setLayers(this.props.layerTypes);\n\n // Parse `google.maps.version` to capture the major version number.\n const versionMatch = maps.version.match(/^3\\.(\\d+)\\./);\n // The major version is the first (and only) captured group.\n const mapsVersion = versionMatch && Number(versionMatch[1]);\n\n // render in overlay\n const this_ = this;\n const overlay = Object.assign(new maps.OverlayView(), {\n onAdd() {\n const K_MAX_WIDTH =\n typeof screen !== 'undefined' ? `${screen.width}px` : '2000px';\n const K_MAX_HEIGHT =\n typeof screen !== 'undefined' ? `${screen.height}px` : '2000px';\n\n const div = document.createElement('div');\n div.style.backgroundColor = 'transparent';\n div.style.position = 'absolute';\n div.style.left = '0px';\n div.style.top = '0px';\n div.style.width = K_MAX_WIDTH; // prevents some chrome draw defects\n div.style.height = K_MAX_HEIGHT;\n\n if (this_.props.overlayViewDivStyle) {\n const { overlayViewDivStyle } = this_.props;\n if (typeof overlayViewDivStyle === 'object') {\n Object.keys(overlayViewDivStyle).forEach((property) => {\n div.style[property] = overlayViewDivStyle[property];\n });\n }\n }\n\n const panes = this.getPanes();\n panes.overlayMouseTarget.appendChild(div);\n this_.geoService_.setMapCanvasProjection(\n maps,\n overlay.getProjection()\n );\n\n if (!IS_REACT_16) {\n createPortal(\n this_,\n this_._renderPortal(),\n div,\n // remove prerendered markers\n () => this_.setState({ overlay: div })\n );\n } else {\n this_.setState({ overlay: div });\n }\n },\n\n onRemove() {\n const renderedOverlay = this_.state.overlay;\n if (renderedOverlay && !IS_REACT_16) {\n ReactDOM.unmountComponentAtNode(renderedOverlay);\n }\n this_.setState({ overlay: null });\n },\n\n draw() {\n this_.updateCounter_++;\n this_._onBoundsChanged(map, maps, !this_.props.debounced);\n\n if (!this_.googleApiLoadedCalled_) {\n this_._onGoogleApiLoaded({ map, maps, ref: this_.googleMapDom_ });\n this_.googleApiLoadedCalled_ = true;\n }\n\n if (this_.mouse_) {\n const latLng = this_.geoService_.fromContainerPixelToLatLng(\n this_.mouse_\n );\n this_.mouse_.lat = latLng.lat;\n this_.mouse_.lng = latLng.lng;\n }\n\n this_._onChildMouseMove();\n\n if (this_.markersDispatcher_) {\n this_.markersDispatcher_.emit('kON_CHANGE');\n if (this_.fireMouseEventOnIdle_) {\n this_.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE');\n }\n }\n },\n });\n\n this.overlay_ = overlay;\n\n overlay.setMap(map);\n if (this.props.heatmap.positions) {\n this.heatmap.setMap(map);\n }\n\n if (this.props.onTilesLoaded) {\n maps.event.addListener(map, 'tilesloaded', () => {\n this_._onTilesLoaded();\n });\n }\n\n maps.event.addListener(map, 'zoom_changed', () => {\n // recalc position at zoom start\n if (this_.geoService_.getZoom() !== map.getZoom()) {\n if (!this_.zoomAnimationInProgress_) {\n this_.zoomAnimationInProgress_ = true;\n this_._onZoomAnimationStart(map.zoom);\n }\n\n // If draw() is not called each frame during a zoom animation,\n // simulate it.\n if (mapsVersion < DRAW_CALLED_DURING_ANIMATION_VERSION) {\n const TIMEOUT_ZOOM = 300;\n\n if (\n new Date().getTime() - this.zoomControlClickTime_ <\n TIMEOUT_ZOOM\n ) {\n // there is strange Google Map Api behavior in chrome when zoom animation of map\n // is started only on second raf call, if was click on zoom control\n // or +- keys pressed, so i wait for two rafs before change state\n\n // this does not fully prevent animation jump\n // but reduce it's occurence probability\n raf(() =>\n raf(() => {\n this_.updateCounter_++;\n this_._onBoundsChanged(map, maps);\n })\n );\n } else {\n this_.updateCounter_++;\n this_._onBoundsChanged(map, maps);\n }\n }\n }\n });\n\n maps.event.addListener(map, 'idle', () => {\n if (this.resetSizeOnIdle_) {\n this._setViewSize();\n const currMinZoom = this._computeMinZoom(options.minZoom);\n\n if (currMinZoom !== this.minZoom_) {\n this.minZoom_ = currMinZoom;\n map.setOptions({ minZoom: currMinZoom });\n }\n\n this.resetSizeOnIdle_ = false;\n }\n\n if (this_.zoomAnimationInProgress_) {\n this_.zoomAnimationInProgress_ = false;\n this_._onZoomAnimationEnd(map.zoom);\n }\n\n this_.updateCounter_++;\n this_._onBoundsChanged(map, maps);\n\n this_.dragTime_ = 0;\n\n if (this_.markersDispatcher_) {\n this_.markersDispatcher_.emit('kON_CHANGE');\n }\n });\n\n maps.event.addListener(map, 'mouseover', () => {\n // has advantage over div MouseLeave\n this_.mouseInMap_ = true;\n });\n\n // an alternative way to know the mouse is back within the map\n // This would not fire when clicking/interacting with google maps\n // own on-map countrols+markers. This handles an edge case for touch devices\n // + 'draggable:false' custom option. See #332 for more details.\n maps.event.addListener(map, 'click', () => {\n this_.mouseInMap_ = true;\n });\n\n maps.event.addListener(map, 'mouseout', () => {\n // has advantage over div MouseLeave\n this_.mouseInMap_ = false;\n this_.mouse_ = null;\n this_.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE');\n });\n\n maps.event.addListener(map, 'drag', () => {\n this_.dragTime_ = new Date().getTime();\n this_._onDrag(map);\n });\n\n maps.event.addListener(map, 'dragend', () => {\n // 'dragend' fires on mouse release.\n // 'idle' listener waits until drag inertia ends before firing `onDragEnd`\n const idleListener = maps.event.addListener(map, 'idle', () => {\n maps.event.removeListener(idleListener);\n this_._onDragEnd(map);\n });\n });\n // user choosing satellite vs roads, etc\n maps.event.addListener(map, 'maptypeid_changed', () => {\n this_._onMapTypeIdChange(map.getMapTypeId());\n });\n })\n .catch((e) => {\n // notify callback of load failure\n this._onGoogleApiLoaded({\n map: null,\n maps: null,\n ref: this.googleMapDom_,\n });\n console.error(e); // eslint-disable-line no-console\n throw e;\n });\n };\n\n _onGoogleApiLoaded = (...args) => {\n if (this.props.onGoogleApiLoaded) {\n if (\n process.env.NODE_ENV !== 'production' &&\n this.props.yesIWantToUseGoogleMapApiInternals !== true\n ) {\n console.warn(\n 'GoogleMap: ' + // eslint-disable-line\n 'Usage of internal api objects is dangerous ' +\n 'and can cause a lot of issues.\\n' +\n 'To hide this warning add yesIWantToUseGoogleMapApiInternals={true} ' +\n 'to this.props.hoverDistance;\n\n _onDrag = (...args) => this.props.onDrag && this.props.onDrag(...args);\n\n _onDragEnd = (...args) =>\n this.props.onDragEnd && this.props.onDragEnd(...args);\n\n _onMapTypeIdChange = (...args) =>\n this.props.onMapTypeIdChange && this.props.onMapTypeIdChange(...args);\n\n _onZoomAnimationStart = (...args) =>\n this.props.onZoomAnimationStart && this.props.onZoomAnimationStart(...args);\n\n _onZoomAnimationEnd = (...args) =>\n this.props.onZoomAnimationEnd && this.props.onZoomAnimationEnd(...args);\n\n _onTilesLoaded = () => this.props.onTilesLoaded && this.props.onTilesLoaded();\n\n _onChildClick = (...args) => {\n if (this.props.onChildClick) {\n return this.props.onChildClick(...args);\n }\n return undefined;\n };\n\n _onChildMouseDown = (hoverKey, childProps) => {\n this.childMouseDownArgs_ = [hoverKey, childProps];\n if (this.props.onChildMouseDown) {\n this.props.onChildMouseDown(hoverKey, childProps, { ...this.mouse_ });\n }\n };\n\n // this method works only if this.props.onChildMouseDown was called\n _onChildMouseUp = () => {\n if (this.childMouseDownArgs_) {\n if (this.props.onChildMouseUp) {\n this.props.onChildMouseUp(...this.childMouseDownArgs_, {\n ...this.mouse_,\n });\n }\n this.childMouseDownArgs_ = null;\n this.childMouseUpTime_ = new Date().getTime();\n }\n };\n\n // this method works only if this.props.onChildMouseDown was called\n _onChildMouseMove = () => {\n if (this.childMouseDownArgs_) {\n if (this.props.onChildMouseMove) {\n this.props.onChildMouseMove(...this.childMouseDownArgs_, {\n ...this.mouse_,\n });\n }\n }\n };\n\n _onChildMouseEnter = (...args) => {\n if (this.props.onChildMouseEnter) {\n return this.props.onChildMouseEnter(...args);\n }\n return undefined;\n };\n\n _onChildMouseLeave = (...args) => {\n if (this.props.onChildMouseLeave) {\n return this.props.onChildMouseLeave(...args);\n }\n return undefined;\n };\n\n _setViewSize = () => {\n if (!this.mounted_) return;\n if (isFullScreen()) {\n this.geoService_.setViewSize(window.innerWidth, window.innerHeight);\n } else {\n const mapDom = ReactDOM.findDOMNode(this.googleMapDom_);\n this.geoService_.setViewSize(mapDom.clientWidth, mapDom.clientHeight);\n }\n this._onBoundsChanged();\n };\n\n _onWindowResize = () => {\n this.resetSizeOnIdle_ = true;\n };\n\n _onMapMouseMove = (e) => {\n if (!this.mouseInMap_) return;\n\n const currTime = new Date().getTime();\n const K_RECALC_CLIENT_RECT_MS = 50;\n\n if (currTime - this.mouseMoveTime_ > K_RECALC_CLIENT_RECT_MS) {\n this.boundingRect_ = e.currentTarget.getBoundingClientRect();\n }\n this.mouseMoveTime_ = currTime;\n\n const mousePosX = e.clientX - this.boundingRect_.left;\n const mousePosY = e.clientY - this.boundingRect_.top;\n\n if (!this.mouse_) {\n this.mouse_ = { x: 0, y: 0, lat: 0, lng: 0 };\n }\n\n this.mouse_.x = mousePosX;\n this.mouse_.y = mousePosY;\n\n const latLng = this.geoService_.fromContainerPixelToLatLng(this.mouse_);\n this.mouse_.lat = latLng.lat;\n this.mouse_.lng = latLng.lng;\n\n this._onChildMouseMove();\n\n if (currTime - this.dragTime_ < K_IDLE_TIMEOUT) {\n this.fireMouseEventOnIdle_ = true;\n } else {\n this.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE');\n this.fireMouseEventOnIdle_ = false;\n }\n };\n\n // K_IDLE_CLICK_TIMEOUT - looks like 300 is enough\n _onClick = (...args) =>\n this.props.onClick &&\n !this.childMouseDownArgs_ &&\n new Date().getTime() - this.childMouseUpTime_ > K_IDLE_CLICK_TIMEOUT &&\n this.dragTime_ === 0 &&\n this.props.onClick(...args);\n\n _onMapClick = (event) => {\n if (this.markersDispatcher_) {\n // support touch events and recalculate mouse position on click\n this._onMapMouseMove(event);\n const currTime = new Date().getTime();\n if (currTime - this.dragTime_ > K_IDLE_TIMEOUT) {\n if (this.mouse_) {\n this._onClick({\n ...this.mouse_,\n event,\n });\n }\n\n this.markersDispatcher_.emit('kON_CLICK', event);\n }\n }\n };\n\n // gmap can't prevent map drag if mousedown event already occured\n // the only workaround I find is prevent mousedown native browser event\n _onMapMouseDownNative = (event) => {\n if (!this.mouseInMap_) return;\n\n this._onMapMouseDown(event);\n };\n\n _onMapMouseDown = (event) => {\n if (this.markersDispatcher_) {\n const currTime = new Date().getTime();\n if (currTime - this.dragTime_ > K_IDLE_TIMEOUT) {\n // Hovered marker detected at mouse move could be deleted at mouse down time\n // so it will be good to force hovered marker recalculation\n this._onMapMouseMove(event);\n this.markersDispatcher_.emit('kON_MDOWN', event);\n }\n }\n };\n\n _onMapMouseDownCapture = () => {\n if (detectBrowser().isChrome) {\n // to fix strange zoom in chrome\n this.zoomControlClickTime_ = new Date().getTime();\n }\n };\n\n _onKeyDownCapture = () => {\n if (detectBrowser().isChrome) {\n this.zoomControlClickTime_ = new Date().getTime();\n }\n };\n\n _isCenterDefined = (center) =>\n center &&\n ((isPlainObject(center) && isNumber(center.lat) && isNumber(center.lng)) ||\n (center.length === 2 && isNumber(center[0]) && isNumber(center[1])));\n\n _onBoundsChanged = (map, maps, callExtBoundsChange) => {\n if (map) {\n const gmC = map.getCenter();\n this.geoService_.setView([gmC.lat(), gmC.lng()], map.getZoom(), 0);\n }\n\n if (\n (this.props.onChange || this.props.onBoundsChange) &&\n this.geoService_.canProject()\n ) {\n const zoom = this.geoService_.getZoom();\n const bounds = this.geoService_.getBounds();\n const centerLatLng = this.geoService_.getCenter();\n\n if (!isArraysEqualEps(bounds, this.prevBounds_, kEPS)) {\n if (callExtBoundsChange !== false) {\n const marginBounds = this.geoService_.getBounds(this.props.margin);\n if (this.props.onBoundsChange) {\n this.props.onBoundsChange(\n this.centerIsObject_\n ? { ...centerLatLng }\n : [centerLatLng.lat, centerLatLng.lng],\n zoom,\n bounds,\n marginBounds\n );\n }\n\n if (this.props.onChange) {\n this.props.onChange({\n center: { ...centerLatLng },\n zoom,\n bounds: {\n nw: {\n lat: bounds[0],\n lng: bounds[1],\n },\n se: {\n lat: bounds[2],\n lng: bounds[3],\n },\n sw: {\n lat: bounds[4],\n lng: bounds[5],\n },\n ne: {\n lat: bounds[6],\n lng: bounds[7],\n },\n },\n marginBounds: {\n nw: {\n lat: marginBounds[0],\n lng: marginBounds[1],\n },\n se: {\n lat: marginBounds[2],\n lng: marginBounds[3],\n },\n sw: {\n lat: marginBounds[4],\n lng: marginBounds[5],\n },\n ne: {\n lat: marginBounds[6],\n lng: marginBounds[7],\n },\n },\n\n size: this.geoService_.hasSize()\n ? {\n width: this.geoService_.getWidth(),\n height: this.geoService_.getHeight(),\n }\n : {\n width: 0,\n height: 0,\n },\n });\n }\n\n this.prevBounds_ = bounds;\n }\n }\n }\n };\n\n _registerChild = (ref) => {\n this.googleMapDom_ = ref;\n };\n\n render() {\n const overlay = this.state.overlay;\n const mapMarkerPrerender = !overlay ? (\n \n ) : null;\n\n return (\n \n \n {IS_REACT_16 && overlay && createPortal(this._renderPortal(), overlay)}\n\n {/* render markers before map load done */}\n {mapMarkerPrerender}\n
\n );\n }\n}\n\nexport default GoogleMap;\n","export const generateHeatmap = (instance, { positions }) =>\n new instance.visualization.HeatmapLayer({\n data: positions.reduce((acc, { lat, lng, weight = 1 }) => {\n acc.push({\n location: new instance.LatLng(lat, lng),\n weight,\n });\n return acc;\n }, []),\n });\n\nexport const optionsHeatmap = (instance, { options = {} }) =>\n Object.keys(options).map((option) => instance.set(option, options[option]));\n","export default function isArraysEqualEps(arrayA, arrayB, eps) {\n if (arrayA && arrayB) {\n for (let i = 0; i !== arrayA.length; ++i) {\n if (Math.abs(arrayA[i] - arrayB[i]) > eps) {\n return false;\n }\n }\n return true;\n }\n return false;\n}\n","import {\n styled\n} from '@volkswagen-onehub/components-core';\nimport { keyframes } from 'styled-components';\nimport { MarkerDimensions } from 'src/feature-app/NewMap/MapGeneralController';\n\n\nconst beatKeyframe = keyframes`\n from {\n opacity: 1;\n transform: translate3d(50%, 50%, 0) scale(0);\n }\n to {\n opacity: 0;\n transform: translate3d(50%, 50%, 0) scale(1);\n }\n`;\n\nexport const Wrapper = styled.div<{ onTop?: boolean }>`\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate3d(-50%, -100%, 0);\n z-index: ${(props) => (props.onTop ? '3' : '2')};\n &.geoloc {\n transform: translate3d(-50%, -50%, 0);\n z-index: 1;\n }\n .circle-beat {\n animation: ${beatKeyframe} 2s ease 0s infinite normal none running;\n }\n`;\n\nexport const TextWrapper = styled(Wrapper as any)`\n /* https://github.com/microsoft/TypeScript/issues/37597#issuecomment-628089901 */\n top: 68%;\n color: #ffffff;\n & div {\n color: #ffffff;\n }\n`;\n\nexport const Img = styled.img<{ markerDimensions: MarkerDimensions }>`\n width: ${(props) => `${props.markerDimensions.width}px`};\n height: ${(props) => `${props.markerDimensions.height}px`};\n &.dealer-marker {\n margin-bottom: 4px;\n }\n`;\n","import React from 'react';\nimport { Wrapper } from 'src/feature-app/NewMap/components/CommonStyledComponents';\n\nexport const CenterMarker = React.memo((props: { lat: number; lng: number }) => {\n return (\n \n \n \n \n \n \n );\n});\n","import { Text } from '@volkswagen-onehub/components-core';\nimport React, { useState } from 'react';\nimport { Points } from 'src/types';\nimport { Img, TextWrapper, Wrapper } from 'src/feature-app/NewMap/components/CommonStyledComponents';\nimport { useMapGeneralController } from 'src/feature-app/NewMap/MapGeneralController';\n\ninterface ClusterMarkerProps {\n lat: number;\n lng: number;\n pointCount: number;\n onClick: any;\n isHover: boolean;\n}\n\nexport const sameClusterId = (selectedPoint: Points, point: Points) => {\n if (selectedPoint?.properties?.parent_cluster_id && point.id) {\n return selectedPoint.properties.parent_cluster_id === point.id;\n }\n return false;\n};\n\nexport const ClusterMarker = React.memo(({ onClick, pointCount, isHover }: ClusterMarkerProps) => {\n const { markerDimensions } = useMapGeneralController();\n const [mouseEntered, setMouseEntered] = useState(false);\n\n return (\n {\n e.preventDefault();\n onClick();\n }}\n onMouseEnter={(e) => {\n e.preventDefault();\n setMouseEntered(true);\n }}\n onMouseLeave={(e) => {\n e.preventDefault();\n setMouseEntered(false);\n }}\n >\n \n \n {pointCount} \n \n \n );\n});\n","import { styled } from '@volkswagen-onehub/components-core';\nimport React, { useState } from 'react';\nimport { Points } from 'src/types';\nimport { Img, Wrapper } from 'src/feature-app/NewMap/components/CommonStyledComponents';\nimport { useMapGeneralController } from 'src/feature-app/NewMap/MapGeneralController';\n\nconst Dot = styled.div<{ greyCard: boolean }>`\n height: 4px;\n width: 4px;\n background-color: ${(props) => (props.greyCard ? '#6A767D' : '#0040c5')};\n border-radius: 100%;\n display: inline;\n position: absolute;\n bottom: 0;\n left: 44%;\n`;\n\ninterface DealerMarkerProps {\n onClick: (event: React.MouseEvent) => void;\n lat: number;\n lng: number;\n isGrey: boolean;\n isActive: boolean;\n isHover: boolean;\n isFavouriteDealer: boolean;\n}\n\nexport const isDealerGrey = (carPickupSelected: boolean, replacementCarSelected: boolean, point: Points) =>\n pickupSelectedAndDealerHasIt(carPickupSelected, point) ||\n replacementCarSelectedAndDealerHasIt(replacementCarSelected, point);\n\nexport const isDealerActive = (selectedPoint: Points, point: Points) =>\n selectedPoint?.properties?.dealer?.kvps === point?.properties?.dealer?.kvps;\n\nexport const isDealerFavourite = (favouriteDealer: Points, point: Points) =>\nfavouriteDealer?.properties?.dealer?.kvps === point?.properties?.dealer?.kvps;\n\nexport const isDealerHovered = (hoverPoint: Points, point: Points) =>\nhoverPoint?.properties?.dealer?.kvps === point?.properties?.dealer?.kvps;\n\nconst pickupSelectedAndDealerHasIt = (carPickupSelected: boolean, point: Points) =>\n carPickupSelected && !point?.properties?.dealer?.dmsInfo?.pickupCarServiceAvailabe;\nconst replacementCarSelectedAndDealerHasIt = (replacementCarSelected: boolean, point: Points) =>\n replacementCarSelected && !point?.properties?.dealer?.dmsInfo?.replacementCarServiceAvailable;\n\nexport const DealerMarker = React.memo(\n ({\n onClick,\n isGrey,\n isActive,\n isHover,\n isFavouriteDealer\n }: DealerMarkerProps) => {\n const markerDimensions = useMapGeneralController().markerDimensions;\n const [mouseEntered, setMouseEntered] = useState(false);\n\n return (\n {\n e.preventDefault();\n setMouseEntered(true);\n }}\n onMouseLeave={(e) => {\n e.preventDefault();\n setMouseEntered(false);\n }}\n onTop={isActive || isHover ||mouseEntered ? true : false}\n >\n \n {isActive ? : null}\n \n );\n }\n);\n","import { Breakpoints, BreakpointWrapper, CTA, styled, ThemeProvider } from '@volkswagen-onehub/components-core';\nimport GoogleMapReact from 'google-map-react';\nimport React, { useEffect, useState } from 'react';\nimport { useSelector } from 'react-redux';\nimport { getGoogleApiKey } from 'src/bff';\nimport { useTrackingManager } from 'src/feature-app/hooks/use-tracking-manager';\nimport { Add, ContactDealer, Locate, Reload, Remove } from 'src/icons-core-imports';\nimport { OneFormState, Points, SelectedTab } from 'src/types';\nimport { mapStyles } from 'src/feature-app/NewMap';\nimport { CenterMarker } from 'src/feature-app/NewMap/components/CenterMarker';\nimport { ClusterMarker, sameClusterId } from 'src/feature-app/NewMap/components/ClusterMarker';\nimport { DealerMarker, isDealerGrey, isDealerActive, isDealerFavourite, isDealerHovered } from 'src/feature-app/NewMap/components/DealerMarker';\nimport { useMapGeneralController } from 'src/feature-app/NewMap/MapGeneralController';\n\nconst RecalcularWrapper = styled.div<{ isPosventa?: boolean }>`\n position: fixed;\n top: ${(props) => (props.isPosventa ? '96px' : '68px')};\n transform: translateX(-50%);\n left: 50%;\n background-color: #ffffff;\n border-radius: 500px;\n width: fit-content;\n @media all and (min-width: 960px) {\n top: 24px;\n transform: translateX(0);\n left: unset;\n right: 183px;\n }\n`;\n\nconst GoogleMaps = styled.div`\n & .gm-control-active[aria-label='Ampliar'] {\n display: none !important;\n }\n\n & .gm-control-active[aria-label='Reducir'] {\n display: none !important;\n }\n\n & .gmnoprint {\n display: none;\n }\n`;\n\ninterface MapHeightWrapperProps {\n isTrigger?: boolean;\n isWidget?: boolean;\n}\n\nconst MapHeigthWrapper = styled.div`\n width: 100%;\n height: ${(props) => (props.isWidget ? '85vh' : props.isTrigger ? 'var(--size-grid020)' : '100vh')};\n\n @media all and (min-width: 560px) {\n height: ${(props) => (props.isWidget ? '82vh' : props.isTrigger ? 'var(--size-grid010)' : '100vh')};\n }\n\n @media all and (min-width: 768px) {\n height: ${(props) => (props.isWidget ? '85vh' : props.isTrigger ? 'var(--size-grid010)' : '100vh')};\n }\n @media all and (min-width: 960px) {\n height: ${(props) => (props.isWidget ? '60vh' : props.isTrigger ? '636px' : '100vh')};\n }\n @media all and (min-width: 1600px) {\n height: ${(props) => (props.isWidget ? '70vh' : props.isTrigger ? '684px' : '100vh')};\n }\n`;\n\ninterface newMapProps {\n searchIsDealer?: boolean;\n setTranslateCarousel?: any;\n translateCarousel?: boolean;\n preSelectedOrderValue?: SelectedTab;\n isTrigger?: boolean;\n preselectedDealerForm?: boolean;\n replacementCarSelected?: boolean;\n carPickupSelected?: boolean;\n isPosventa?: boolean;\n isWidget?: boolean;\n}\n\nexport const NewMap = React.memo((props: newMapProps) => {\n const {\n centerRef,\n clusters,\n handleApiLoaded,\n geoLocatedCenterRef,\n getNewClusters,\n handlePointClickAndCarouselMove,\n selectedPoint,\n handleClusterClick,\n mapMaxZoom,\n searchMoreDealers,\n handleMapMovement,\n setSearchIsDealer,\n hoverPoint,\n handleHoverPoint,\n userIsGeoLocated,\n mapHasMoved,\n } = useMapGeneralController();\n const { dealersInfo, formInfo } = useSelector((state: OneFormState) => state);\n const { dealersOrInstallationsMode, favouriteDealer } = dealersInfo;\n const { suggestionIsAddress } = formInfo;\n const {\n searchIsDealer,\n setTranslateCarousel,\n preSelectedOrderValue,\n isTrigger,\n carPickupSelected,\n replacementCarSelected,\n isPosventa,\n isWidget,\n } = props;\n const trackingManager = useTrackingManager();\n\n const [gelocalizationActive, setGelocalizationActive] = useState(false);\n\n useEffect(() => {\n if (userIsGeoLocated) {\n setGelocalizationActive(true);\n } else {\n setGelocalizationActive(false);\n }\n }, [userIsGeoLocated]);\n\n return (\n // Important! Always set the container height explicitly\n \n \n {\n handleApiLoaded(map, maps);\n }}\n defaultCenter={{\n lat: 40.58869349456487,\n lng: -3.0047240000000075,\n }}\n yesIWantToUseGoogleMapApiInternals\n onDrag={() => {\n handleMapMovement();\n }}\n defaultZoom={5}\n options={{\n styles: mapStyles,\n clickableIcons: false,\n streetViewControl: false,\n fullscreenControl: false,\n mapTypeControl: false,\n maxZoom: mapMaxZoom,\n }}\n >\n {clusters\n ? clusters.map((point: Points) => {\n if (point.geometry) {\n const [longitude, latitude] = point.geometry.coordinates;\n return point.properties.cluster ? (\n {\n handleClusterClick(point);\n }}\n pointCount={point.properties.point_count}\n />\n ) : (\n {\n e.preventDefault();\n if (!searchIsDealer) {\n handlePointClickAndCarouselMove(point, true, preSelectedOrderValue);\n }\n }}\n />\n );\n }\n return null;\n })\n : null}\n {(geoLocatedCenterRef.current && gelocalizationActive) || (suggestionIsAddress && centerRef.current) ? (\n \n ) : null}\n \n {isTrigger ? (\n \n \n \n ) : (\n <>\n \n \n \n {clusters && mapHasMoved && !isWidget ? (\n searchIsDealer ? (\n \n \n {\n e.preventDefault();\n setSearchIsDealer(false);\n\n trackingManager.trackFormButtonClick({\n contentId:\n dealersOrInstallationsMode === 'dealers'\n ? 'Ver más talleres cerca'\n : 'Ver más concesionarios cerca',\n });\n searchMoreDealers();\n if (setTranslateCarousel) {\n setTranslateCarousel(false);\n }\n e.stopPropagation();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n >\n {dealersOrInstallationsMode === 'dealers'\n ? 'Ver más talleres cerca'\n : 'Ver más concesionarios cerca'}\n \n \n \n ) : (\n \n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick({\n contentId: 'Buscar en esta zona',\n });\n getNewClusters();\n {\n /*if (setTranslateCarousel) {\n setTranslateCarousel(false);\n }*/\n }\n e.stopPropagation();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n >\n Buscar en esta zona\n \n \n \n )\n ) : null}\n >\n )}\n \n \n );\n});\n\n/* MAP CONTROLLLERS (!el botón de geolocaclización en versión mobile está en la propia vista. \n Estos controladores actualmente solo están visibles a partir de 960px)\n*/\nconst ControllerBackground = styled.div`\n border-radius: 100%;\n background-color: #ffffff;\n height: 44px;\n width: 44px;\n`;\n\ninterface ControllersWrapperProps {\n isTrigger?: boolean;\n}\n\nconst ControllersWrapper = styled.div`\n position: ${(props) => (props.isTrigger ? 'absolute' : 'absolute')};\n bottom: ${(props) => (props.isTrigger ? '24px' : '240px')};\n right: ${(props) => (props.isTrigger ? 'calc(var(--size-grid002) + 24px)' : '20px')};\n\n @media all and (min-width: 960px) {\n bottom: 24px;\n right: ${(props) => (props.isTrigger ? 'calc(var(--size-grid002) + 24px)' : '24px')};\n }\n @media all and (min-width: 1920px) {\n right: ${(props) => (props.isTrigger ? 'calc(var(--size-grid003) + 24px)' : '24px')};\n }\n @media all and (min-width: 2560px) {\n right: ${(props) => (props.isTrigger ? 'calc(var(--size-grid004) + 24px)' : '24px')};\n }\n`;\n\nconst ZoomWrapper = styled.div`\n display: flex;\n flex-direction: column;\n margin-top: 14px;\n\n & div {\n margin: 6px 0px;\n }\n`;\n\nconst IconLess = 'https://cdn.volkswagen.es/repository/app/vw-oneform/assets/icons/ic_less.svg';\nconst IconMore = 'https://cdn.volkswagen.es/repository/app/vw-oneform/assets/icons/ic_more.svg';\n\nconst Controllers = (props: { gelocalizationActive: boolean; suggestionIsAddress: boolean; isTrigger?: boolean }) => {\n const { handleChangeInMapZoom, centerInGeoLocatedCenter, centerRef, centerMap } = useMapGeneralController();\n\n const { gelocalizationActive, isTrigger, suggestionIsAddress } = props;\n\n return (\n \n \n {gelocalizationActive || (suggestionIsAddress && centerRef.current) ? (\n \n {\n e.preventDefault();\n if (suggestionIsAddress && centerRef.current) {\n centerMap(centerRef.current);\n } else {\n centerInGeoLocatedCenter();\n }\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n ) : null}\n \n \n {\n e.preventDefault();\n handleChangeInMapZoom(true);\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n \n {\n e.preventDefault();\n handleChangeInMapZoom(false);\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n \n \n \n );\n};\n","import { styled } from '@volkswagen-onehub/components-core';\nimport React, { ReactElement, useEffect, useRef } from 'react';\nimport Slider from 'react-slick';\nimport { NewDealerCard } from 'src/feature-app';\nimport { Points } from 'src/types';\nimport { useMapGeneralController } from 'src/feature-app/NewMap/MapGeneralController';\nimport { getDistanceFromLatLngCenter } from 'src/feature-app/NewMap/utils';\n\nconst CSSDiv = styled.div`\n /* Slider */\n .slick-slider {\n position: relative;\n\n display: block;\n box-sizing: border-box;\n\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n\n -webkit-touch-callout: none;\n -khtml-user-select: none;\n -ms-touch-action: pan-y;\n touch-action: pan-y;\n -webkit-tap-highlight-color: transparent;\n }\n\n .slick-list {\n position: relative;\n\n display: block;\n overflow: hidden;\n\n margin: 0;\n padding: 0;\n }\n .slick-list:focus {\n outline: none;\n }\n .slick-list.dragging {\n cursor: pointer;\n cursor: hand;\n }\n\n .slick-slider .slick-track,\n .slick-slider .slick-list {\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n -ms-transform: translate3d(0, 0, 0);\n -o-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n }\n\n .slick-track {\n position: relative;\n top: 0;\n left: 0;\n\n display: block;\n }\n .slick-track:before,\n .slick-track:after {\n display: table;\n\n content: '';\n }\n .slick-track:after {\n clear: both;\n }\n .slick-loading .slick-track {\n visibility: hidden;\n }\n\n .slick-slide {\n display: none;\n float: left;\n\n height: 100%;\n min-height: 1px;\n }\n [dir='rtl'] .slick-slide {\n float: right;\n }\n .slick-slide img {\n display: block;\n }\n .slick-slide.slick-loading img {\n display: none;\n }\n .slick-slide.dragging img {\n pointer-events: none;\n }\n .slick-initialized .slick-slide {\n display: block;\n }\n .slick-loading .slick-slide {\n visibility: hidden;\n }\n .slick-vertical .slick-slide {\n display: block;\n\n height: auto;\n\n border: 1px solid transparent;\n }\n .slick-arrow.slick-hidden {\n display: none;\n }\n\n /* Slider */\n .slick-slider {\n position: relative;\n\n display: block;\n box-sizing: border-box;\n\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n\n -webkit-touch-callout: none;\n -khtml-user-select: none;\n -ms-touch-action: pan-y;\n touch-action: pan-y;\n -webkit-tap-highlight-color: transparent;\n }\n\n .slick-list {\n position: relative;\n\n display: block;\n overflow: hidden;\n\n margin: 0;\n padding: 0;\n }\n .slick-list:focus {\n outline: none;\n }\n .slick-list.dragging {\n cursor: pointer;\n cursor: hand;\n }\n\n .slick-slider .slick-track,\n .slick-slider .slick-list {\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n -ms-transform: translate3d(0, 0, 0);\n -o-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n }\n\n .slick-track {\n position: relative;\n top: 0;\n left: 0;\n\n display: block;\n }\n .slick-track:before,\n .slick-track:after {\n display: table;\n\n content: '';\n }\n .slick-track:after {\n clear: both;\n }\n .slick-loading .slick-track {\n visibility: hidden;\n }\n\n .slick-slide {\n display: none;\n float: left;\n\n height: 100%;\n min-height: 1px;\n }\n [dir='rtl'] .slick-slide {\n float: right;\n }\n .slick-slide img {\n display: block;\n }\n .slick-slide.slick-loading img {\n display: none;\n }\n .slick-slide.dragging img {\n pointer-events: none;\n }\n .slick-initialized .slick-slide {\n display: block;\n }\n .slick-loading .slick-slide {\n visibility: hidden;\n }\n .slick-vertical .slick-slide {\n display: block;\n\n height: auto;\n\n border: 1px solid transparent;\n }\n .slick-arrow.slick-hidden {\n display: none;\n }\n`;\n\nconst BackgroundCard = styled.div`\n background-color: #001e50;\n margin: 0 4px;\n`;\n\ninterface CarouselCardsProps {\n handleShowCalendarOnClick?: any;\n handleSeleccionarOnClick: any;\n handleShowSlots?: (point: Points) => string | null;\n pointsToList: Points[];\n isCitaPosventa?: boolean;\n replacementCarSelected?: boolean;\n carPickupSelected?: boolean;\n}\n\nexport const Carousel = (props: CarouselCardsProps) => {\n const {\n clusters,\n handlePointClickAndCarouselMove,\n centerToCalculateDistance,\n handleSelectedPoint,\n handleClusterClick,\n selectedPoint,\n } = useMapGeneralController();\n const { \n handleSeleccionarOnClick, \n handleShowCalendarOnClick, \n handleShowSlots, \n pointsToList, \n isCitaPosventa,\n carPickupSelected,\n replacementCarSelected \n } = props;\n const sliderRef = useRef(null);\n const childrenRef = useRef(null);\n\n useEffect(() => {\n if (pointsToList.length) {\n const firstPoint = selectedPoint ? selectedPoint : pointsToList[0];\n // handleCarouselMovement(firstPoint);\n handleSelectedPoint(firstPoint);\n // handleSelectedCard(firstPoint);\n }\n }, [pointsToList]);\n\n useEffect(() => {\n // Movimiento del carousel en caso de que se haga click en un Dealer Marker.\n if (selectedPoint) {\n // handleSelectedCard(selectedPoint);\n handleCarouselMovement(selectedPoint);\n }\n }, [selectedPoint, pointsToList]);\n\n const handleSelectedCard = (point: Points) => {\n if (!point.properties.cluster) {\n const { kvps } = point.properties.dealer;\n\n const index = pointsToList.findIndex((dealer) => {\n if (dealer.properties.dealer.kvps === kvps) {\n return true;\n }\n });\n sliderRef.current.slickGoTo(index);\n }\n };\n\n const handleCarouselMovement = (point: Points) => {\n if (point.properties.parent_cluster_id) {\n const parentCluster = clusters.find(\n (cluster) => cluster.properties.cluster && cluster.id === point.properties.parent_cluster_id\n );\n if (parentCluster) {\n // En caso de que el dealer esté dentro de un cluster dentro de otro fijamos el valor de isCluster como true para que llegue hasta el final\n // y no rompa únicamente el primer cluster.\n // handleClusterClick(point, true);\n handleSelectedPoint(point);\n } else {\n handlePointClickAndCarouselMove(point, false);\n handleSelectedCard(point);\n }\n } else {\n handlePointClickAndCarouselMove(point, false);\n handleSelectedCard(point);\n }\n };\n\n const settings = {\n className: 'center',\n infinite: false,\n centerMode: true,\n centerPadding: '60px',\n slidesToShow: 1,\n swipe: true,\n speed: 500,\n arrows: false,\n beforeChange: (current: number, next: number) => {\n const point: Points = pointsToList.find((point) => {\n if (!point.properties.cluster) {\n if (point.properties.dealer.kvps === childrenRef.current[next].key) {\n return point;\n }\n }\n });\n\n handleCarouselMovement(point);\n },\n };\n return (\n \n {\n sliderRef.current = el;\n if (el && el.props && el.props.children) {\n childrenRef.current = el.props.children.filter((c:any) => c !== null);\n }\n }}\n >\n {pointsToList\n ? pointsToList.map((point: Points, i) => {\n const distanceFromCenter = getDistanceFromLatLngCenter(centerToCalculateDistance.current, point);\n\n return !point.properties.cluster ? (\n \n {/* este div es necesario para el funcionamiento de la libreria */}\n \n \n \n
\n ) : null;\n })\n : null}\n \n \n );\n};\n","import {\n Breakpoints,\n Container,\n ContainerHorizontalAlignment,\n ContainerPadding,\n ContainerWrap,\n CTA,\n Layout,\n styled,\n Text,\n TextAlignment,\n TextAppearance,\n ThemeProvider,\n} from '@volkswagen-onehub/components-core';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport { useDispatch, useSelector, useStore } from 'react-redux';\nimport { Suggest, useFeatureAppConfig, useMapGeneralController } from 'src/feature-app';\nimport { Horario, Installation, isDealerData, OneFormState, SelectedTab } from 'src/types';\nimport { isGooglePlace, updateMapVariables, Suggestion } from 'src/feature-app/NewMap';\nimport {\n useTrackingManager,\n useLocateUser,\n useShowOverflow,\n useFeatureAppEnvironment,\n useFeatureServices,\n} from 'src/feature-app/hooks';\nimport LoadScriptInstance from 'src/feature-app/NewMap/Loadscript';\nimport { renderAvisoIslasCanariasLayer } from 'src/components';\nimport { getGeocode } from 'src/feature-app/NewMap/utils';\nimport { GooglePlace } from 'src/feature-app/NewMap/components/suggest';\n\nconst FiltrosWrapper = styled.div<{ onlySuggest?: boolean; showOverflow?: boolean }>`\n min-height: 100vh;\n position: relative;\n padding-bottom: 117px;\n padding-top: 56px;\n overflow: ${(props) => (props.showOverflow ? 'visible' : 'auto')};\n .filtros {\n &__header {\n text-align: center;\n }\n &__body {\n flex-grow: 1;\n padding-bottom: ${(props) => (props.onlySuggest ? '4px' : null)};\n }\n &__controls {\n position: fixed;\n bottom: 0;\n width: 100%;\n padding: 14px 0;\n background: #ffffff;\n border-top: 1px solid #dfe4e8;\n }\n }\n`;\n\nconst MultipleCTAWrapper = styled.div`\n text-align: left;\n & > button {\n margin: 24px 24px 0 0;\n }\n`;\n\nconst Divider = styled.div`\n background-color: #dfe4e8;\n width: 100vw;\n height: 1px;\n margin-bottom: 14px;\n\n @media all and (min-width: 960px) {\n display: none;\n margin-bottom: 0;\n }\n`;\n\n//revisar width aButtonsWrapper a partir de 960 en navegadores/dispositivos con barra de scroll.\n//Está puesto con valor fijo porqué por algun motivo no pilla bien el 100%\n\nconst ActionButtonsWrapper = styled.div`\n display: flex;\n justify-content: flex-end;\n @media all and (min-width: 960px) {\n width: 400px;\n }\n button {\n div {\n font-size: 14px;\n }\n &:first-of-type {\n margin-right: 32px;\n }\n }\n`;\n\ninterface FiltrosProps {\n closeFiltros: any;\n showFiltros: boolean;\n setShowFiltros: React.Dispatch>;\n setPreSelectedOrderValue?: React.Dispatch>;\n preSelectedOrderValue?: SelectedTab;\n onlySuggest?: boolean;\n concesionario?: boolean;\n citaPosventa?: boolean;\n}\n\nexport const Filtros = (props: FiltrosProps) => {\n return (\n {}}>\n \n \n );\n};\n\nexport interface SelectedSuggestion {\n name: string;\n suggestion: Suggestion;\n}\n\nconst getSelectedSuggestion = (suggestion: Suggestion) => {\n if (isGooglePlace(suggestion)) {\n return { name: suggestion.name, suggestion };\n } else {\n if (!isDealerData(suggestion)) {\n return {\n name: `${(suggestion as Installation).TXT_V_Installation_Data_Name__c}, ${\n (suggestion as Installation).TXT_V_Address__c\n }`,\n suggestion,\n };\n } else {\n return {\n name: `${suggestion.name}, ${suggestion.markerInfo.dealerInfo.address}`,\n suggestion,\n };\n }\n }\n};\n\nexport const FiltrosComponent = (props: FiltrosProps) => {\n const {\n closeFiltros,\n showFiltros,\n setShowFiltros,\n setPreSelectedOrderValue,\n preSelectedOrderValue,\n onlySuggest,\n concesionario,\n citaPosventa,\n } = props;\n const { formData, formInfo } = useSelector((state: OneFormState) => state);\n\n //Si se necesita que el overflow sea visible. Selectsno nativos, suggests, etc. Añadir en la definicion del step showOverflow.\n\n const { showOverflow } = useShowOverflow(false);\n\n const [aplicarDisabled, setAplicarDisabled] = useState(true);\n const [tabsOrder, setTabsOrder] = useState('horario');\n const [currentHorario, setCurrentHorario] = useState<{ label: string; value: string }>({\n label: 'Lo antes posible',\n value: 'before',\n });\n // guardar suggestion seleccionada previo a hacer submit\n // sirve para activar o desactivar el setAplicarDisabled\n const [selectedSuggestion, setSelectedSuggestion] = useState(null);\n const { register } = useFormContext();\n const trackingManager = useTrackingManager();\n const filtrosRef = useRef(null);\n\n const { userSuggestion: userSuggest, suggestionIsInCanaryIslands } = formInfo;\n\n const CTAsHorario = [\n { label: 'Lo antes posible', value: 'before' },\n { label: 'Por la mañana', value: 'morning' },\n { label: 'Al mediodía', value: 'afternon' },\n { label: 'Por la tarde', value: 'evening' },\n ];\n\n const CTAsOrden: { value: SelectedTab; label: string }[] = [\n { value: 'ubicacion', label: 'Ubicación' },\n { value: 'horario', label: 'Horario' },\n ];\n\n const {\n value,\n setValue,\n icon,\n locationSuccess,\n setLocationSuccess,\n loading,\n locationDisabled,\n isLocating,\n handleLocateFilters,\n } = useLocateUser();\n const dispatch = useDispatch();\n\n const { moreDealersSearched, setMoreDealersSearched } = useMapGeneralController();\n const { trigger } = useFeatureAppConfig();\n const store = useStore();\n const env = useFeatureAppEnvironment();\n const layerManager = useFeatureServices()['layer-manager'];\n\n const validateSubmission = () => {\n const { suggestionIsInCanaryIslands } = store.getState().formInfo;\n\n if (suggestionIsInCanaryIslands) {\n renderAvisoIslasCanariasLayer(store, env, layerManager);\n return;\n }\n\n if (preSelectedOrderValue && setPreSelectedOrderValue && tabsOrder !== preSelectedOrderValue) {\n setPreSelectedOrderValue(tabsOrder);\n }\n setShowFiltros(false);\n };\n\n const handleFiltrosSubmit = (selectedSuggestionFromClick?: SelectedSuggestion) => {\n if (selectedSuggestion && !selectedSuggestionFromClick) {\n // if (isGooglePlace(selectedSuggestion.suggestion) && selectedSuggestion.suggestion.isGeoLocated) {\n // // Parche para que se actualize la ubicación a la geolocalización. El bug viene de que en use-locate-user.tsx\n // // se detecta el cambio de suggestion en un useeffect y eso dispara la función updateMapVariables, pero en el caso de\n // // la geolocalización, ésta función se dispara automáticamente al clickar sobre el cta. Si queremos esperar a que los cambios\n // // se hagan efectivos al clickar \"Aplicar filtros\" hay que llamarla desde aquí.\n\n updateMapVariables(dispatch, selectedSuggestion.suggestion).then(() => {\n validateSubmission();\n });\n }\n // Pasamos este valor al seleccionar en la lista desplegable un valor.\n if (selectedSuggestionFromClick) {\n updateMapVariables(dispatch, selectedSuggestionFromClick.suggestion).then(() => {\n validateSubmission();\n });\n }\n };\n\n useEffect(() => {\n if (!moreDealersSearched) {\n if (userSuggest && showFiltros) {\n if (!isGooglePlace(userSuggest) && isDealerData(userSuggest)) {\n setValue(`${userSuggest?.name}, ${userSuggest?.markerInfo?.dealerInfo?.address}`);\n } else if (!isGooglePlace(userSuggest) && !isDealerData(userSuggest)) {\n setValue(\n `${(userSuggest as Installation)?.TXT_V_Installation_Data_Name__c}, ${\n (userSuggest as Installation)?.TXT_V_Address__c\n }`\n );\n } else {\n setValue(userSuggest?.name);\n }\n }\n } else {\n setValue('');\n }\n if (showFiltros) setAplicarDisabled(true);\n }, [showFiltros]);\n\n useEffect(() => {\n if (value && !aplicarDisabled) {\n if (value !== selectedSuggestion.name) {\n setAplicarDisabled(true);\n }\n }\n }, [value]);\n\n useEffect(() => {\n const val = CTAsHorario.find((el: any) => formData.fields.horario === el.value);\n setCurrentHorario(val);\n }, [formData]);\n\n useEffect(() => {\n if (preSelectedOrderValue) {\n setTabsOrder(preSelectedOrderValue);\n }\n }, [preSelectedOrderValue]);\n\n useEffect(() => {\n if (moreDealersSearched && locationSuccess) setLocationSuccess(false);\n }, [moreDealersSearched]);\n\n useEffect(() => {\n // Necesario para que cada vez que se selecciona un resultado de google en filtros se compruebe si\n // pertenece a las islas canarias y dispare el popup antes de que se apliquen los filtros.\n const checkGeocode = async () => {\n const geometry = await getGeocode(selectedSuggestion);\n };\n if (selectedSuggestion?.suggestion?.isGooglePlace) {\n checkGeocode();\n }\n }, [selectedSuggestion]);\n\n useEffect(() => {\n if (!moreDealersSearched) {\n // cuando se monta la componente, si está geolocalizado forzar el locationSuccess a\n // true porque el boton el hook se resetea al montar de nuevo la componente\n // también porque en mobile la componente Filtros se renderiza cada vez que se abre\n if (!userSuggest) {\n return;\n }\n if ((userSuggest as GooglePlace)?.isGeoLocated) {\n setLocationSuccess(true);\n }\n if (!isGooglePlace(userSuggest) && isDealerData(userSuggest)) {\n setValue(`${userSuggest.name}, ${userSuggest.markerInfo.dealerInfo.address}`);\n } else if (!isGooglePlace(userSuggest) && !isDealerData(userSuggest)) {\n setValue(\n `${(userSuggest as Installation).TXT_V_Installation_Data_Name__c}, ${\n (userSuggest as Installation).TXT_V_Address__c\n }`\n );\n } else {\n setValue(userSuggest.name);\n }\n }\n }, []);\n\n const onSuggestionSelectedFn = (suggestion: Suggestion) => {\n const selectedSuggestion = getSelectedSuggestion(suggestion);\n setSelectedSuggestion(selectedSuggestion);\n setLocationSuccess(false);\n setAplicarDisabled(false);\n if (moreDealersSearched) setMoreDealersSearched(false);\n // Cierra la parte de filtros\n handleFiltrosSubmit(selectedSuggestion);\n };\n\n return (\n \n \n \n {citaPosventa ? null : (\n \n \n Filtros\n \n
\n )}\n\n {!onlySuggest ? (\n \n
\n \n {citaPosventa ? (\n <>Buscar de nuevo>\n ) : (\n <>Busca tu {!concesionario ? taller : concesionario }>\n )}\n \n \n \n
\n \n {\n e.preventDefault();\n if (!locationSuccess) {\n const { suggestion } = await handleLocateFilters();\n setSelectedSuggestion({ name: suggestion.name, suggestion });\n setAplicarDisabled(false);\n setMoreDealersSearched(false);\n }\n }}\n disabled={loading ? true : false}\n size=\"small\"\n >\n Localiza mi posición actual\n \n {locationDisabled ? (\n \n \n Tu localización está deshabilitada\n \n
\n ) : null}\n \n {/* */}\n \n {/*
*/}\n
\n ) : (\n \n
\n \n {citaPosventa ? (\n <>Buscar de nuevo>\n ) : (\n <>Busca tu {!concesionario ? taller : concesionario }>\n )}\n \n \n \n
\n \n {\n e.preventDefault();\n if (!locationSuccess) {\n const { suggestion } = await handleLocateFilters();\n setSelectedSuggestion({ name: suggestion.name, suggestion });\n setAplicarDisabled(false);\n setMoreDealersSearched(false);\n }\n }}\n disabled={loading ? true : false}\n size=\"small\"\n >\n Localiza mi posición actual\n \n {locationDisabled ? (\n \n \n Tu localización está deshabilitada\n \n
\n ) : null}\n \n \n
\n )}\n \n \n
\n \n {\n closeFiltros();\n trackingManager.trackFormButtonClick({\n contentId: 'Cancelar',\n });\n }}\n ariaLabel=\"aria label\"\n >\n Cancelar\n \n {\n e.preventDefault();\n trackingManager.trackFormButtonClick({\n contentId: 'Aplicar filtros',\n });\n setTimeout(() => {\n handleFiltrosSubmit();\n }, 1000);\n }}\n ariaLabel=\"aria label\"\n disabled={aplicarDisabled}\n >\n {citaPosventa ? <>Buscar> : <>Aplicar filtros>}\n \n \n \n
\n \n \n );\n};\n\ninterface SortByProps {\n setTabsOrder: React.Dispatch>;\n setAplicarDisabled: React.Dispatch>;\n preSelectedOrderValue: SelectedTab;\n CTAsOrden: {\n value: SelectedTab;\n label: string;\n }[];\n tabsOrder: SelectedTab;\n}\n\nconst SortBy = (props: SortByProps) => {\n const { setTabsOrder, setAplicarDisabled, preSelectedOrderValue, tabsOrder, CTAsOrden } = props;\n const trackingManager = useTrackingManager();\n\n return (\n <>\n \n Ordenar por\n \n \n {CTAsOrden.map((el) => {\n return (\n {\n e.preventDefault();\n trackingManager.trackFormButtonClick({\n contentId: el.label,\n });\n setTabsOrder(el.value);\n if (preSelectedOrderValue !== el.value) {\n setAplicarDisabled(false);\n }\n }}\n size=\"small\"\n key={el.value}\n >\n {el.label}\n \n );\n })}\n \n >\n );\n};\n\ninterface ChangeHorarioProps {\n setCurrentHorario: React.Dispatch>;\n setAplicarDisabled: React.Dispatch>;\n CTAsHorario: {\n label: string;\n value: string;\n }[];\n currentHorario: { label: string; value: string };\n horario: Horario;\n}\n\nconst ChangeHorario = (props: ChangeHorarioProps) => {\n const { setCurrentHorario, setAplicarDisabled, CTAsHorario, currentHorario, horario } = props;\n const trackingManager = useTrackingManager();\n\n return (\n \n \n Selecciona una franja horaria\n \n \n {CTAsHorario.map((cta: { label: string; value: string }) => {\n return (\n {\n e.preventDefault();\n trackingManager.trackFormButtonClick({\n contentId: cta.label,\n });\n if (cta.label !== currentHorario.label) {\n setCurrentHorario(cta);\n }\n if (cta.value !== horario) {\n setAplicarDisabled(false);\n }\n }}\n size=\"small\"\n key={cta.value}\n >\n {cta.label}\n \n );\n })}\n \n \n );\n};\n","import { Text, TextAppearance, TextColor, ThemeProvider } from '@volkswagen-onehub/components-core';\nimport { Close, ContactDealer, Magnifier, Route } from 'src/icons-core-imports';\nimport { MagnifierLabel, CloseButton, SuggestionWrapper, StyledWrapper } from '.';\nimport React, { useEffect, useRef, useState } from 'react';\nimport Autosuggest from 'react-autosuggest';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { DealersData } from 'src/types';\nimport { useAddressPredictions } from 'src/feature-app';\nimport { DealersOrInstallationsMode, Geometry, Installation, isDealerData, OneFormState } from 'src/types';\nimport { useOneFormContext } from 'src/feature-app/OneForm';\nimport { isGooglePlace } from 'src/feature-app/NewMap/utils';\nimport { useDropdowPosition, useTrackingManager } from 'src/feature-app/hooks';\nexport interface GooglePlace {\n isGooglePlace: boolean;\n name: string;\n isGeoLocated: boolean;\n skipSearch?: boolean;\n moreDealersSearched?: boolean;\n geometry?: Geometry;\n}\n\nexport type Suggestion = DealersData | GooglePlace;\n\n// https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Special_Characters\nconst escapeRegexCharacters = (str: string) => {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n\nconst getSuggestions = (\n list: DealersData[] | Installation[],\n value: string,\n dealersOrInstallationsMode: DealersOrInstallationsMode\n) => {\n if (value.length < 2) return [];\n const escapedValue = escapeRegexCharacters(value.trim());\n\n if (escapedValue === '') {\n return [];\n }\n const regex = new RegExp(escapedValue, 'i');\n\n if (dealersOrInstallationsMode === 'dealers') {\n return list.filter((dealer: DealersData) => regex.test(dealer.markerInfo.dealerInfo.name));\n } else {\n return list.filter((installation: Installation) => regex.test(installation.TXT_V_Installation_Data_Name__c));\n }\n};\n\nconst getSuggestionValue = (suggestion: Suggestion) => {\n if (isGooglePlace(suggestion)) {\n return suggestion.name;\n } else {\n if (isDealerData(suggestion)) {\n return suggestion.markerInfo.dealerInfo.name;\n } else {\n return (suggestion as Installation).TXT_V_Installation_Data_Name__c;\n }\n }\n};\n\nconst renderSuggestion = (suggestion: Suggestion) => {\n if (isGooglePlace(suggestion)) {\n return (\n \n \n \n {suggestion.name}\n \n \n );\n } else {\n let name;\n let address;\n let zipCode;\n let city;\n let province;\n if (isDealerData(suggestion)) {\n name = suggestion.markerInfo.dealerInfo.name;\n address = suggestion.markerInfo.dealerInfo.address;\n zipCode = suggestion.markerInfo.dealerInfo.zipCode;\n city = suggestion.markerInfo.dealerInfo.city;\n province = suggestion.markerInfo.dealerInfo.province;\n } else {\n name = (suggestion as Installation).TXT_V_Installation_Data_Name__c;\n address = (suggestion as Installation).TXT_V_Address__c;\n zipCode = (suggestion as Installation).TXT_V_Postal_Code__c;\n city = (suggestion as Installation).TXT_V_Location__c;\n province = (suggestion as Installation).TXT_Code_Concession__c;\n }\n return (\n \n \n \n \n \n {name}\n \n \n {address}\n \n {zipCode} {city}, {province}\n \n
\n \n );\n }\n};\n\nconst getValueFormatted = (suggestion: Suggestion) => {\n if (isGooglePlace(suggestion)) {\n return suggestion.name;\n }\n if (!isGooglePlace(suggestion) && isDealerData(suggestion)) {\n return `${suggestion.name}, ${suggestion.markerInfo.dealerInfo.address}`;\n } else if (!isGooglePlace(suggestion) && !isDealerData(suggestion)) {\n return `${(suggestion as Installation).TXT_V_Installation_Data_Name__c}, ${\n (suggestion as Installation).TXT_V_Address__c\n }`;\n } else {\n return '';\n }\n};\n\ninterface SuggestProps {\n setSuggestion?: React.Dispatch>;\n setValue: React.Dispatch>;\n setAplicarDisabled?: React.Dispatch>;\n value: string;\n isFiltrosSuggest?: boolean;\n isLocating?: boolean;\n moreDealersSearched?: boolean;\n setLocationSuccess?: React.Dispatch>;\n formTheme?: string;\n onSuggestionSelectedFn?: (suggestion: Suggestion) => void;\n autoWidth?: boolean;\n}\n\nexport function Suggest(props: SuggestProps) {\n const {\n setSuggestion,\n setValue,\n value,\n isFiltrosSuggest,\n setAplicarDisabled,\n isLocating,\n moreDealersSearched,\n setLocationSuccess,\n formTheme,\n onSuggestionSelectedFn,\n autoWidth\n } = props;\n const [suggestions, setSuggestions] = useState([]);\n const [selectedValue, setSelectedValue] = useState(false); // Controla que una vez seleccionado un valor en el input, no siga buscando en google maps.\n const predictions = useAddressPredictions(value, selectedValue);\n const [inputPlaceholder, setInputPlaceHolder] = useState('Localidad, código postal o nombre del taller');\n const trackingManager = useTrackingManager();\n const suggestRef = useRef(null);\n const inputRef = useRef(null);\n\n const { formInfo, dealersInfo } = useSelector((state: OneFormState) => state);\n const { dealers, installations, dealersOrInstallationsMode } = dealersInfo;\n\n const [inputFocus, setInputFocus] = useState(false);\n const dispatch = useDispatch();\n const { setDisableIntroNextStep, setError, handleNextStep } = useOneFormContext();\n\n useEffect(() => {\n if (isFiltrosSuggest) {\n setDisableIntroNextStep(true);\n // inputRef.current.input.addEventListener('keydown', handleIntroKeyDown)\n }\n return () => {\n if (isFiltrosSuggest) {\n setDisableIntroNextStep(false);\n // inputRef.current.input.removeEventListener('keydown', handleIntroKeyDown)\n }\n };\n }, []);\n\n const onChange = (e: any, { newValue }: { newValue: string }) => {\n e.stopPropagation();\n if (setSelectedValue) {\n setSelectedValue(false);\n }\n setError(false);\n setValue(newValue);\n };\n\n //desplegar el dropdown para arriba o para abajo según la posicinón del input en el window\n const { goUp, getAndUpdateState } = useDropdowPosition('.react-autosuggest__container');\n\n const onClick = () => {\n getAndUpdateState();\n\n trackingManager.trackFormFieldClick(\n {\n contentId: 'Localidad, código postal o nombre del taller',\n },\n {\n FormFieldName: 'location', // Corregir\n }\n );\n };\n\n const onSuggestionsFetchRequested = async ({ value }: { value: string }) => {\n const list = dealersOrInstallationsMode === 'dealers' ? dealers : installations;\n const dealerSuggestions = getSuggestions(list, value, dealersOrInstallationsMode);\n setSuggestions(dealerSuggestions);\n };\n\n const onSuggestionsClearRequested = () => {\n setSuggestions([]);\n };\n\n const [placeHolder, setPlaceHolder] = useState('');\n\n useEffect(() => {\n if (dealersOrInstallationsMode === 'dealers') {\n setPlaceHolder('Localidad, código postal, dirección, nombre del taller, etc.');\n } else {\n setPlaceHolder('Localidad, código postal o nombre del concesionario');\n }\n }, []);\n\n useEffect(() => {\n if (isFiltrosSuggest && moreDealersSearched) {\n setInputPlaceHolder('Zona del mapa seleccionada');\n } else {\n setInputPlaceHolder(placeHolder);\n }\n }, [moreDealersSearched, placeHolder]);\n\n const inputProps = {\n placeholder: inputPlaceholder,\n value,\n onChange,\n onClick,\n disabled: isLocating ? true : false,\n };\n\n // REFACTORIZAR\n useEffect(() => {\n if (selectedValue) return;\n const predictionsFormatted: GooglePlace[] = predictions.map((prediction) => {\n return {\n name: prediction,\n isGooglePlace: true,\n isGeoLocated: false,\n };\n });\n setSuggestions([...suggestions, ...predictionsFormatted]);\n }, [predictions]);\n\n return (\n {\n setInputFocus(true);\n }}\n onBlur={() => setInputFocus(false)}\n isFullScreen={formInfo.notALayer ? true : false}\n goUp={goUp}\n autoWidth={autoWidth}\n className=\"styled-wrapper-suggest\"\n >\n \n \n \n {\n if (!isGooglePlace(suggestion)) {\n dispatch({ type: 'SUGGESTION_IS_IN_CANARY_ISLANDS', payload: false });\n }\n const value = getValueFormatted(suggestion);\n setValue(value);\n setSelectedValue(true);\n if (onSuggestionSelectedFn) {\n setTimeout(() => {\n onSuggestionSelectedFn(suggestion);\n }, 0);\n }\n }}\n inputProps={inputProps}\n />\n {value !== '' && (\n \n {\n e.preventDefault();\n setValue('');\n if (!isFiltrosSuggest && !isLocating) {\n setLocationSuccess(false);\n setSuggestion(null);\n setValue('');\n setSelectedValue(false);\n } else if (isFiltrosSuggest) {\n setAplicarDisabled(true);\n }\n }}\n >\n \n \n \n )}\n \n );\n}\n","export const mapStyles = [\n {\n elementType: 'geometry',\n stylers: [\n {\n color: '#f5f5f5',\n },\n ],\n },\n {\n elementType: 'labels.icon',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#616161',\n },\n ],\n },\n {\n elementType: 'labels.text.stroke',\n stylers: [\n {\n color: '#f5f5f5',\n },\n ],\n },\n {\n featureType: 'administrative.land_parcel',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'administrative.land_parcel',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#bdbdbd',\n },\n ],\n },\n {\n featureType: 'landscape',\n stylers: [\n {\n color: '#dfe4e8',\n },\n ],\n },\n {\n featureType: 'landscape.natural',\n elementType: 'labels',\n stylers: [\n {\n color: '#757575',\n },\n {\n visibility: 'simplified',\n },\n {\n weight: 0.5,\n },\n ],\n },\n {\n featureType: 'poi',\n elementType: 'geometry',\n stylers: [\n {\n color: '#eeeeee',\n },\n ],\n },\n {\n featureType: 'poi',\n elementType: 'labels.text',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'poi',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#757575',\n },\n ],\n },\n {\n featureType: 'poi.business',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'poi.park',\n elementType: 'geometry',\n stylers: [\n {\n color: '#e5e5e5',\n },\n ],\n },\n {\n featureType: 'poi.park',\n elementType: 'geometry.fill',\n stylers: [\n {\n color: '#ade5a1',\n },\n ],\n },\n {\n featureType: 'poi.park',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'poi.park',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#00662f',\n },\n ],\n },\n {\n featureType: 'poi.park',\n elementType: 'labels.text.stroke',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'road',\n elementType: 'geometry',\n stylers: [\n {\n color: '#ffffff',\n },\n ],\n },\n {\n featureType: 'road',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road',\n elementType: 'labels.icon',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'road.arterial',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road.arterial',\n elementType: 'labels.icon',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road.arterial',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#757575',\n },\n ],\n },\n {\n featureType: 'road.highway',\n elementType: 'geometry',\n stylers: [\n {\n color: '#dadada',\n },\n ],\n },\n {\n featureType: 'road.highway',\n elementType: 'geometry.fill',\n stylers: [\n {\n color: '#ffe856',\n },\n ],\n },\n {\n featureType: 'road.highway',\n elementType: 'geometry.stroke',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'road.highway',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road.highway',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#616161',\n },\n ],\n },\n {\n featureType: 'road.local',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'road.local',\n elementType: 'geometry',\n stylers: [\n {\n color: '#ffffff',\n },\n {\n visibility: 'on',\n },\n {\n weight: 0.5,\n },\n ],\n },\n {\n featureType: 'road.local',\n elementType: 'labels',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road.local',\n elementType: 'labels.text',\n stylers: [\n {\n visibility: 'on',\n },\n ],\n },\n {\n featureType: 'road.local',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#9e9e9e',\n },\n ],\n },\n {\n featureType: 'transit',\n stylers: [\n {\n visibility: 'off',\n },\n ],\n },\n {\n featureType: 'transit.line',\n elementType: 'geometry',\n stylers: [\n {\n color: '#e5e5e5',\n },\n ],\n },\n {\n featureType: 'transit.station',\n elementType: 'geometry',\n stylers: [\n {\n color: '#eeeeee',\n },\n ],\n },\n {\n featureType: 'water',\n elementType: 'geometry',\n stylers: [\n {\n color: '#4cc7f4',\n },\n ],\n },\n {\n featureType: 'water',\n elementType: 'labels.text.fill',\n stylers: [\n {\n color: '#0066a1',\n },\n ],\n },\n];\n","import {\n styled\n} from '@volkswagen-onehub/components-core';\n\n//Layer styles\n\nexport const MapAndTabsWrapper = styled.div<{ showFilters: boolean }>`\n display: flex;\n .wrapper {\n width: 50%;\n height: 100vh;\n &--tabs {\n background-color: #001e50;\n overflow-y: hidden;\n color: white;\n }\n &--map {\n z-index: 4;\n height: 100%;\n background-color: grey;\n }\n }\n .opacity-layer {\n position: absolute;\n width: 50%;\n height: 100%;\n left: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: ${(props) => (props.showFilters ? 6 : -1)};\n opacity: ${(props) => (props.showFilters ? 1 : 0)};\n transition: opacity 0.4s;\n }\n`;\n\nexport const FilterButton = styled.div`\n position: absolute;\n top: 24px;\n right: 24px;\n button {\n background: #ffffff;\n }\n`;\n\nexport const FiltrosWrapperLayer = styled.div`\n min-height: 100vh;\n width: 50%;\n background-color: white;\n position: absolute;\n top: 0;\n right: 0;\n z-index: 5;\n transform: translate3d(100%, 0, 0);\n display: none;\n .back-btn {\n position: absolute;\n z-index: 4;\n top: 20px;\n left: 24px;\n @media screen and (min-width: 1600px) {\n top: 24px;\n }\n }\n &.filtros-enter {\n display: block;\n transform: translate3d(100%, 0, 0);\n }\n &.filtros-enter-active {\n display: block;\n transform: translate3d(0, 0, 0);\n transition: all 0.4s;\n }\n &.filtros-enter-done {\n display: block;\n transform: translate3d(0, 0, 0);\n }\n &.filtros-exit {\n display: block;\n transform: translate3d(0, 0, 0);\n }\n &.filtros-exit-active {\n display: block;\n transform: translate3d(100%, 0, 0);\n transition: all 0.4s;\n }\n &.filtros-exit-done {\n display: none;\n transform: translate3d(100%, 0, 0);\n }\n`;\n\nexport const ListWrapper = styled.div<{paddingBottom?: string}>`\n height: calc(100vh - 120px);\n overflow-y: auto;\n @media all and (min-width: 960px) {\n padding-bottom: ${(props)=> props.paddingBottom ? props.paddingBottom : null};\n }\n`;\n\nexport const SmallerSVG = styled.div`\n svg {\n height: 12px;\n width: 12px;\n }\n button {\n height: 24px;\n min-height: 24px; \n }\n div{\n font-size: 12px;\n }\n`;\n\n//Mobile Layer styled components\n\nexport const FilterMobileNavbar = styled.div`\n position: fixed;\n top: 0;\n width: 100vw;\n padding: 8px 20px;\n z-index: 20;\n background-color: #ffffff; \n`;\n\nexport const CTAsNavigationWrapper = styled.div<{services?: boolean}>`\n display:flex;\n justify-content: space-between;\n padding-bottom: ${(props) => props.services ? '16px' : null} ;\n`;\n\ninterface VerMasYCarouselPositionProps {\n translateCarousel: boolean;\n userIsGeoLocated: boolean;\n}\n\nexport const VerMasYCarouselPosition = styled.div`\n position: absolute;\n bottom: 8px;\n height: fit-content;\n width: 100%;\n`;\nexport const SoloCardWrapper = styled.div`\n background-color: #001e50;\n bottom: 8px;\n height: fit-content;\n position: absolute;\n margin: 0 var(--size-grid002);\n width: var(--size-grid020);\n .box-card-wrapper {\n border: none;\n margin-top: 0;\n }\n`;\n\nexport const CTASwrapper = styled.div`\n padding-right: 20px;\n padding-bottom: 12px;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n`;\n\nexport const VerMasTalleresCTA = styled.div`\n height: 32px;\n padding-right: 16px;\n padding-left: 16px;\n background-color: #ffffff;\n border: 1px solid #001e50;\n border-radius: 500px;\n color: #001e50;\n display: flex;\n align-items: center;\n width: 100px;\n`;\n\nexport const ControllerBackground = styled.div`\n border-radius: 100%;\n background-color: #ffffff;\n height: 44px;\n width: 44px;\n margin-bottom: 12px;\n button {\n border: 1px solid #001e50;\n }\n`;\n\ninterface CloseButtonProps {\n isTabsClose?: boolean;\n isFiltrosClose?: boolean;\n}\nexport const CloseButtonWrapper = styled.div`\n position: absolute;\n padding-bottom: ${(props) => (props.isTabsClose || props.isFiltrosClose ? '12px' : null)};\n background-color: ${(props) => (props.isTabsClose ? '#001E50' : '#FFFFFF')};\n width: 100%;\n padding-top: 12px;\n padding-left: 12px;\n z-index: 4;\n top: ${(props) => (props.isTabsClose || props.isFiltrosClose ? '0' : null)};\n @media screen and (min-width: 560px) {\n left: 20px;\n }\n button {\n color: ${(props) => (props.isTabsClose ? '#FFFFFF' : null)};\n }\n`;\n\nexport const MoblieListWrapper = styled.div<{paddingTop?: string}>`\n padding-top: ${(props)=> props.paddingTop ? props.paddingTop : null};\n`;\n","import {\n Breakpoints,\n Container,\n ContainerGutter,\n ContainerHorizontalAlignment,\n ContainerPadding,\n CTA,\n Layout,\n ThemeProvider,\n} from '@volkswagen-onehub/components-core';\nimport { ArrowLeft, Magnifier, FleetServicePrivate, CarPickupService } from 'src/icons-core-imports';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { CSSTransition } from 'react-transition-group';\nimport { useFeatureAppConfig } from 'src/feature-app';\nimport { CloseComponent } from 'src/feature-app/Screen';\nimport { SelectedTab } from 'src/types';\nimport { Filtros } from 'src/feature-app/NewMap';\nimport { Points } from 'src/types';\nimport { useOneFormContext } from 'src/feature-app/OneForm';\nimport { NewMap } from 'src/feature-app/NewMap/components/Map';\nimport { useMapGeneralController } from 'src/feature-app/NewMap/MapGeneralController';\nimport { \n MapAndTabsWrapper, \n FilterButton, \n FiltrosWrapperLayer, \n ListWrapper, \n SmallerSVG, \n handleClickCarPickup,\n handleClickReplacementCar \n} from '.';\n\ninterface ViewCitaPosventaProps {\n handleSeleccionarOnClick: any;\n handleShowSlots?: (point: Points) => string | null;\n renderPoints(points: any, carPickupSelected?: boolean, replacementCarSelected?: boolean, isTime?: boolean ): JSX.Element[];\n renderCalendar?(): JSX.Element;\n showCalendar?: boolean;\n preSelectedOrderValue?: SelectedTab;\n setPreSelectedOrderValue?: React.Dispatch>;\n pointsToList: Points[];\n services?: boolean;\n paddingBottomList?: string;\n isPosventa?: boolean;\n concesionario?: boolean;\n onlySuggest?: boolean; \n}\n\nexport const LayerDesktopView = (props: ViewCitaPosventaProps) => {\n const {\n renderPoints,\n renderCalendar,\n showCalendar,\n preSelectedOrderValue,\n setPreSelectedOrderValue,\n pointsToList,\n services, paddingBottomList, isPosventa, concesionario, onlySuggest,\n } = props;\n\n const [showFiltros, setShowFiltros] = useState(false);\n const [ preselectedDealerForm, setPreselectedDealerForm ] = useState(false);\n const config = useFeatureAppConfig();\n const sustitucionRef = useRef(null);\n const recogidaRef = useRef(null);\n\n useEffect(()=>{\n if(config.trigger === 'cita-posventa-dealer') {\n setPreselectedDealerForm(true);\n } else {\n setPreselectedDealerForm(false);\n }\n }, []);\n\n const { searchIsDealer } = useMapGeneralController();\n const { handleAreYouSureLayer } = useOneFormContext();\n\n const handleShowFiltros = () => {\n setShowFiltros(!showFiltros);\n };\n\n //seleccionar los que tiene coche de sustitucion o servicio de recogida\n\n const [ carPickupSelected, setCarPickupSelected] = useState(false);\n const [ replacementCarSelected, setReplacementCarSelected ] = useState(false);\n\n return showCalendar ? (\n renderCalendar()\n ) : (\n \n \n \n
\n {\n services? (\n
\n \n {\n e.preventDefault();\n handleClickReplacementCar(replacementCarSelected, setReplacementCarSelected);\n sustitucionRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Coche de sustitución\n \n \n \n {\n e.preventDefault();\n handleClickCarPickup(carPickupSelected, setCarPickupSelected);\n recogidaRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Servicio de recogida y entrega\n \n \n \n ) : null\n }\n
\n \n {pointsToList ? (\n \n \n {renderPoints(pointsToList, carPickupSelected, replacementCarSelected)}\n \n \n ) : null}\n
\n \n
\n \n \n {\n preselectedDealerForm ? null : (\n \n \n {\n e.preventDefault();\n handleShowFiltros();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n >\n Buscar de nuevo\n \n \n \n )\n } \n
\n setShowFiltros(false)} />\n \n\n
\n \n \n \n
{\n e.preventDefault();\n handleShowFiltros();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n handleShowFiltros()}\n showFiltros={showFiltros}\n setShowFiltros={setShowFiltros}\n setPreSelectedOrderValue={setPreSelectedOrderValue}\n preSelectedOrderValue={preSelectedOrderValue}\n citaPosventa = {isPosventa}\n onlySuggest={true}\n concesionario={true}\n />\n \n \n \n \n );\n};\n","import {\n Breakpoints,\n Container,\n ContainerHorizontalAlignment,\n ContainerPadding,\n ContainerWrap,\n ContainerGutter,\n CTA,\n Layout,\n styled,\n Text,\n TextAppearance,\n ThemeProvider,\n} from '@volkswagen-onehub/components-core';\nimport { ArrowLeft, Close, Locate, Magnifier, CarPickupService, FleetServicePrivate } from 'src/icons-core-imports';\n\nimport React, { useEffect, useState } from 'react';\nimport { useFeatureAppConfig } from 'src/feature-app';\nimport { SelectedTab } from 'src/types';\nimport { Carousel, Filtros, NewMap, useMapGeneralController } from 'src/feature-app/NewMap';\nimport { Points } from 'src/types';\nimport { useOneFormContext } from 'src/feature-app/OneForm';\nimport { useRef } from 'react';\nimport { \n CloseButtonWrapper, \n ControllerBackground, \n CTAsNavigationWrapper, \n CTASwrapper, \n FilterMobileNavbar, \n SmallerSVG, \n SoloCardWrapper, \n VerMasTalleresCTA, \n VerMasYCarouselPosition,\n handleClickCarPickup,\n handleClickReplacementCar,\n MoblieListWrapper \n} from '.';\nimport { useFeatureServices } from 'src/feature-app/hooks';\n\nconst listIcon = require('../../../feature-app/NewMap/assets/filter-ic_list.svg');\n\ninterface ViewCitaPosventaProps {\n handleSeleccionarOnClick: any;\n handleShowSlots?: (point: Points) => string | null;\n handleShowCalendarOnClick?: (point: Points) => Promise
;\n renderPoints(points: any, carPickupSelected?: boolean, replacementCarSelected?: boolean, isTime?: boolean, isCarouselCard?: boolean ): JSX.Element[];\n renderCalendar?(): JSX.Element;\n showCalendar?: boolean;\n preSelectedOrderValue?: SelectedTab;\n setPreSelectedOrderValue?: React.Dispatch>;\n pointsToList: Points[];\n isPosventa?: boolean;\n services?: boolean;\n concesionario?: boolean;\n onlySuggest?: boolean; \n paddingTopList?: string;\n}\n\nexport const LayerMobileView = (props: ViewCitaPosventaProps) => {\n const {\n handleSeleccionarOnClick,\n handleShowSlots,\n renderPoints,\n handleShowCalendarOnClick,\n showCalendar,\n renderCalendar,\n preSelectedOrderValue,\n setPreSelectedOrderValue,\n pointsToList, isPosventa, services,\n concesionario, onlySuggest, paddingTopList\n } = props;\n const { handlePreviousStep } = useOneFormContext();\n\n const {\n centerInGeoLocatedCenter,\n userIsGeoLocated,\n searchIsDealer,\n } = useMapGeneralController();\n\n //controladores de vista\n\n const [showFiltros, setShowFiltros] = useState(false);\n const [showTalleres, setShowTalleres] = useState(false);\n const [showMap, setShowMap] = useState(true);\n const [translateCarousel, setTranselateCarousel] = useState(false);\n const [ preselectedDealerForm, setPreselectedDealerForm ] = useState(false);\n const config = useFeatureAppConfig();\n const sustitucionMapRef = useRef(null);\n const recogidaMapRef = useRef(null);\n const sustitucionRef = useRef(null);\n const recogidaRef = useRef(null);\n const layerManager = useFeatureServices()['layer-manager'];\n useEffect(()=>{\n if(config.trigger === 'cita-posventa-dealer') {\n setPreselectedDealerForm(true);\n } else {\n setPreselectedDealerForm(false);\n }\n }, []);\n\n //otros\n const [gelocalizationActive, setGelocalizationActive] = useState(false);\n\n useEffect(() => {\n if (userIsGeoLocated) {\n setGelocalizationActive(true);\n }\n }, [userIsGeoLocated]);\n\n const handleShowFiltros = () => {\n setShowFiltros(!showFiltros);\n setShowTalleres(false);\n };\n const handleShowTalleres = () => {\n setShowTalleres(!showTalleres);\n setShowFiltros(false);\n };\n\n useEffect(() => {\n if (showFiltros === false && showTalleres === false) {\n setShowMap(true);\n } else {\n setShowMap(false);\n }\n }, [showFiltros, showTalleres]);\n\n //seleccionar los que tiene coche de sustitucion o servicio de recogida\n\n const [ carPickupSelected, setCarPickupSelected] = useState(false);\n const [ replacementCarSelected, setReplacementCarSelected ] = useState(false);\n\n return showCalendar ? (\n renderCalendar()\n ) : (\n \n {showMap ? (\n <>\n
\n \n \n {\n e.preventDefault();\n const layers = layerManager.getLayers();\n const layer = layers.find(\n (layer) => layer.layer.options.id === 'mapaLeadInPage'\n ); \n if (layer) {\n layer.layer?.close();\n }\n handlePreviousStep(e);\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n {\n preselectedDealerForm ? null : (\n {\n e.preventDefault();\n handleShowFiltros();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n >\n Buscar de nuevo\n \n )\n }\n \n {\n services ? (\n \n \n {\n e.preventDefault();\n handleClickReplacementCar(replacementCarSelected, setReplacementCarSelected);\n sustitucionMapRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Coche de sustitución\n \n \n \n {\n e.preventDefault();\n handleClickCarPickup(replacementCarSelected, setReplacementCarSelected);\n recogidaMapRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Servicio de recogida\n \n \n \n ) : null\n }\n \n \n
\n \n
\n\n {pointsToList ? (\n searchIsDealer ? (\n
\n {renderPoints(pointsToList, carPickupSelected, replacementCarSelected)}\n \n ) : (\n
\n \n \n {gelocalizationActive ? (\n {\n e.preventDefault();\n centerInGeoLocatedCenter();\n e.stopPropagation();\n }}\n >\n {\n e.preventDefault();\n centerInGeoLocatedCenter();\n e.stopPropagation();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n ) : null}\n {\n e.preventDefault();\n e.stopPropagation();\n }}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleShowTalleres();\n }}\n >\n \n \n Ver lista\n \n \n \n \n\n {/* Aunque en principio no debería devolver nunca sólo un resultado, dejo el siguiente\n render condicional por is acaso */}\n {pointsToList.length === 1 ? (\n \n {renderPoints(pointsToList, carPickupSelected, replacementCarSelected)}\n \n ) : (\n \n )}\n \n )\n ) : null}\n >\n ) : (\n <>\n {showTalleres ? (\n
\n \n \n {\n e.preventDefault();\n handleShowTalleres();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n {\n services ? (\n \n \n {\n e.preventDefault();\n handleClickReplacementCar(replacementCarSelected, setReplacementCarSelected);\n sustitucionRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Coche de sustitución\n \n \n \n {\n e.preventDefault();\n handleClickCarPickup(carPickupSelected, setCarPickupSelected);\n recogidaRef.current.blur();\n }} \n ariaLabel='aria label'\n icon={ }\n >\n Servicio de recogida\n \n \n \n ) : null\n }\n \n \n \n \n {renderPoints(pointsToList, carPickupSelected, replacementCarSelected)}\n \n \n \n
\n \n ) : showFiltros ? (\n
\n \n \n {\n e.preventDefault();\n handleShowFiltros();\n }}\n ariaLabel=\"aria label\"\n icon={ }\n />\n \n handleShowFiltros()}\n preSelectedOrderValue={preSelectedOrderValue}\n setPreSelectedOrderValue={setPreSelectedOrderValue}\n showFiltros={showFiltros}\n setShowFiltros={setShowFiltros}\n citaPosventa = {isPosventa}\n onlySuggest={onlySuggest}\n concesionario={concesionario}\n />\n
\n \n ) : null}\n >\n )}\n
\n );\n};\n","export const handleClickCarPickup = (carPickupSelected: boolean, setCarPickupSelected: (value: boolean) => void ) => {\n if(!carPickupSelected) {\n setCarPickupSelected(true);\n } else {\n setCarPickupSelected(false);\n }\n};\n\nexport const handleClickReplacementCar = (replacementCarSelected: boolean, setReplacementCarSelected: (value: boolean) => void) => {\n if(!replacementCarSelected) {\n setReplacementCarSelected(true);\n } else {\n setReplacementCarSelected(false);\n }\n};\n","export * from './BajaComunicaciones';\nexport * from './CallMe';\nexport * from './Cem';\nexport * from './CitaPosventa';\nexport * from './Empresa';\nexport * from './FormsAdhoc';\nexport * from './LEM';\nexport * from './Leads';\nexport * from './LeadsInPage';\nexport * from './MGM';\nexport * from './Newsletter';\nexport * from './NoCompra';\nexport * from './NoRenovacion';\nexport * from './Prospects';\nexport * from './Race';\nexport * from './SAC';\nexport * from './dps-utils';\nexport * from './format-fields';\nexport * from './helpers';\nexport * from './SAC/SACOneShop';\n\n","!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):t.dayjs=e()}(this,function(){\"use strict\";var t=\"millisecond\",e=\"second\",n=\"minute\",r=\"hour\",i=\"day\",s=\"week\",u=\"month\",a=\"quarter\",o=\"year\",f=\"date\",h=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[^0-9]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?.?(\\d+)?$/,c=/\\[([^\\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,d={name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\")},$=function(t,e,n){var r=String(t);return!r||r.length>=e?t:\"\"+Array(e+1-r.length).join(n)+t},l={s:$,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?\"+\":\"-\")+$(r,2,\"0\")+\":\"+$(i,2,\"0\")},m:function t(e,n){if(e.date() {\n return {\n url: window ? window.location.href : undefined,\n name: name ? name : undefined,\n };\n};\n\nexport const createPartner = (store: Store, dealerData?: DealersData): TrackingPartner => {\n const { formData, dealersInfo } = store.getState();\n const { dealer } = formData.fields;\n const { selectedDealer } = dealersInfo;\n\n const dealerFromStore = dealer ? dealer : selectedDealer ? selectedDealer : undefined;\n\n const dealerToUse = dealerData ? dealerData : dealerFromStore;\n\n return {\n informationBnr: dealerToUse?.kvps,\n informationDepartment: undefined,\n informationZIP: dealerToUse?.markerInfo?.dealerInfo?.zipCode,\n informationName: dealerToUse?.name,\n };\n};\n\nexport const createPartnerWithSearch = (store: Store, dealerData?: DealersData): TrackingPartner => {\n const { formData, formInfo } = store.getState();\n const basePartner = createPartner(store, dealerData);\n const SearchType = formInfo.suggestionIsDealer\n ? 'DealerSuggestion'\n : !formInfo.suggestionIsDealer\n ? 'GooglePlacesSuggestion'\n : undefined;\n\n return {\n ...basePartner,\n SearchSearchTerm: formData.fields.location,\n SearchType,\n SearchNumberOfResults: undefined,\n };\n};\n\nconst getStepNumber = (formInfo: FormInfo) => {\n const { step } = formInfo;\n\n if (!step) return undefined;\n\n return String(step.screenIndex + 1);\n};\n\nconst getStepName = (formInfo: FormInfo, processInfo?: TrackingProcess): string | undefined => {\n if (processInfo) return processInfo.StepName;\n\n const { step, multiStepScreenIndex, multiSteps } = formInfo;\n\n if (!step) return undefined;\n if (step.multiStep && multiStepScreenIndex >= 0) return multiSteps[multiStepScreenIndex].name; // Devolvemos el nombre del step dentro del multsitep.\n\n return step.name ? step.name : undefined;\n};\n\nexport const createTrackingProcess = (store: Store, processInfo?: TrackingProcess): TrackingProcess => {\n const { formInfo } = store.getState();\n\n let StepName = getStepName(formInfo, processInfo);\n let StepNumber = getStepNumber(formInfo);\n\n return {\n StepName,\n StepNumber,\n };\n};\n\nexport const getFormAppointments = (store: Store): TrackingForm => {\n const { formData } = store.getState();\n const { slot }: { slot?: Slot } = formData.fields;\n\n let Appointments;\n let NumberOfAppointments;\n\n if (slot) {\n Appointments = [dayjs(slot.from).utc().format('YYYY-MM-DDTHH:mm:ss[Z]')];\n NumberOfAppointments = 1;\n }\n return {\n Appointments,\n NumberOfAppointments,\n };\n};\n\nexport const getMarketingConsent = (store: Store): TrackingForm => {\n const { formData } = store.getState();\n const { lssi, tmk } = formData.fields;\n\n if (!lssi || !tmk) {\n return {\n MarketingConsent: [],\n };\n }\n\n return {\n MarketingConsent: [\n {\n comunicaciones: lssi === 'PERMITE',\n perfilado: tmk === 'PERMITE',\n },\n ],\n };\n};\n\nexport const getBaseEventInfo = (store: Store, brand: 'V' | 'N'): TrackingEventInfo => {\n const { pageCategory } = store.getState().formData.fields;\n\n const baseEventInfo: TrackingEventInfo = {\n brand: brand === 'N' ? 'commercial' : 'passenger',\n pageCategory,\n sectionName: undefined,\n templateType: 'Feature App Template',\n };\n return baseEventInfo;\n};\n\nexport const getCompleteConfigurationFromVicci = (vicciData: VicciData): TrackingConfiguration => {\n if (!vicciData) return emptyConfigurationFromVicci;\n\n const { vehicleConfiguration } = vicciData.consolidatedData;\n const { COD_VEH_WHEELS, DESC_VEH_WHEELS } = getWheelsParams(vicciData.featuresData.vehicleCatalogue.features);\n return {\n ...emptyConfigurationFromVicci,\n ModelId: vehicleConfiguration.modelKey.split('$')[0],\n ModelModelVersion: vehicleConfiguration.modelVersion,\n ModelName: vehicleConfiguration.modelName,\n ModelYear: vehicleConfiguration.modelYear,\n ExteriorColorCode: vehicleConfiguration.exterior?.code,\n ExteriorColorName: vehicleConfiguration.exterior?.name,\n InteriorColorCode: vehicleConfiguration.interior?.code,\n InteriorColorName: vehicleConfiguration.interior?.name,\n WheelsBasicId: COD_VEH_WHEELS,\n WheelsBasicName: DESC_VEH_WHEELS,\n };\n};\n\nexport const getCarlineConfigurationFromVicci = (vicciData: VicciData): TrackingConfiguration => {\n if (!vicciData) return {};\n\n const { vehicleConfiguration } = vicciData.consolidatedData;\n\n return {\n CarlineId: vehicleConfiguration.carlineKey,\n CarlineName: vehicleConfiguration.carlineName,\n SalesgroupId: vehicleConfiguration.salesgroupKey,\n SalesgroupName: vehicleConfiguration.salesgroupName,\n EquipmentlineName: getEquipmentlineName(vehicleConfiguration.modelFilters),\n };\n};\n\nexport const getCarlineConfigurationFromMkc = (marketingCode: any): TrackingConfiguration => {\n if (!marketingCode) return {};\n\n const { carlineKey, carlineName, salesgroupKey, salesgroupName, modelFilters } = marketingCode.consolidatedData;\n\n return {\n CarlineId: carlineKey,\n CarlineName: carlineName,\n SalesgroupId: salesgroupKey,\n SalesgroupName: salesgroupName,\n EquipmentlineName: getEquipmentlineName(modelFilters),\n };\n};\n\nexport const getCarlineConfiguration = (store: Store): TrackingConfiguration => {\n const { dealersInfo, formData } = store.getState();\n const { selectedCarline, oferta, salesGroup, match } = dealersInfo;\n const { vicciData, matchMarketingCodeData, marketingCodeResponse } = formData.fields;\n\n if (vicciData) {\n return getCarlineConfigurationFromVicci(vicciData);\n }\n\n if (marketingCodeResponse) {\n return getCarlineConfigurationFromMkc(marketingCodeResponse);\n }\n\n let configuration: TrackingConfiguration = {};\n if (selectedCarline) {\n configuration = {\n CarlineId: String(selectedCarline.code),\n CarlineName: selectedCarline.title,\n };\n }\n if (oferta) {\n configuration = {\n ...configuration,\n CarlineId: String(oferta.carlineCode),\n CarlineName: oferta.carlineTitle,\n };\n }\n if (salesGroup) {\n configuration = {\n ...configuration,\n SalesgroupId: salesGroup.salesGroupId,\n SalesgroupName: salesGroup.salesGroupName,\n };\n }\n\n if (match && matchMarketingCodeData) {\n configuration = {\n ...configuration,\n ...getDataFromMarketingCode(matchMarketingCodeData),\n };\n }\n return configuration;\n};\n\nexport const getDataFromMarketingCode = (marketingCodeData: StoredConfigurationResponse) => {\n return {\n SalesgroupId: marketingCodeData?.vehicleConfiguration?.salesgroupKey,\n SalesgroupName: marketingCodeData?.consolidatedData?.salesgroupName,\n EquipmentlineName: getEquipmentlineName(marketingCodeData?.consolidatedData?.modelFilters),\n ModelId: marketingCodeData?.vehicleConfiguration?.modelKey.split('$')[0],\n ModelName: marketingCodeData?.consolidatedData?.modelName,\n ModelYear: marketingCodeData?.vehicleConfiguration?.modelYear,\n };\n};\n","import { isMobileOnly, isTablet } from 'react-device-detect';\n\nexport const getParamsForm = () => {\n let tc: string;\n if (typeof s !== 'undefined') {\n tc = s.persCmp ? s.persCmp : '';\n } else {\n tc = '';\n }\n\n const date = new Date();\n const today = date.toISOString().slice(0, 10) + ' ' + date.toLocaleString('es-ES').slice(-8);\n const referalUrl = document.referrer.substring(0, 30);\n const url = window.location.origin + window.location.pathname;\n const device = isMobileOnly ? 'mobile' : isTablet ? 'tablet' : 'desktop';\n\n return {\n tc,\n today,\n referalUrl,\n url,\n device,\n };\n};\n","import { styled, Text, TextAlignment, TextAppearance, TextColor } from '@volkswagen-onehub/components-core';\n// // import store from './store';\nimport { CloseHandleV2, FocusLayerSizeV2 } from '@volkswagen-onehub/layer-manager';\nimport React, { SyntheticEvent, useEffect, useState } from 'react';\nimport { deviceType } from 'react-device-detect';\nimport { FormContext, useForm } from 'react-hook-form';\nimport { useDispatch, useSelector, useStore } from 'react-redux';\nimport { setObjectValues, useFeatureServices, formInfoInitialState } from 'src/feature-app';\nimport { TIME_FOR_TRANSFORM } from 'src/globals';\nimport { FormDataGroup, FormInfo, OneFormState, Steps } from 'src/types';\nimport { ErrorFormFields } from './tracking-types';\nimport { useTrackingManager } from 'src/feature-app/hooks/use-tracking-manager';\nimport { BehaviorSubject, config } from 'rxjs';\nimport { useFeatureAppConfig, useFeatureAppEnvironment } from './hooks';\nimport { removeConfigurationHash } from './remove-configuration-hash';\nimport { GenericErrorLayer, AvisoIslasCanarias, renderAvisoIslasCanariasLayer } from 'src/components';\nimport { LayerManagerWrapper } from './LayerManagerWrapper';\n\nconst Form = styled.form``;\n\ninterface errorMessageProps {\n notALayer: boolean;\n}\nconst ErrorMessage = styled.div`\n position: absolute;\n bottom: ${(props) => (props.notALayer ? '88px' : '122px')};\n right: 20px;\n z-index: 1000;\n width: max-content;\n padding: 4px 8px;\n border-radius: 4px;\n background-color: #e4002c;\n color: #ffffff;\n @media all and (min-width: 560px) {\n right: ${(props) => (props.notALayer ? 'var(--size-grid002)' : '40px')};\n }\n @media all and (min-width: 960px) {\n right: ${(props) => (props.notALayer ? 'var(--size-grid003)' : '52px')};\n bottom: ${(props) => (props.notALayer ? '88px' : '136px')};\n }\n @media all and (min-width: 1280px) {\n right: ${(props) => (props.notALayer ? 'var(--size-grid005)' : '52px')};\n }\n @media all and (min-width: 1920px) {\n right: ${(props) => (props.notALayer ? 'var(--size-grid006)' : '52px')};\n }\n @media all and (min-width: 2560px) {\n right: ${(props) => (props.notALayer ? 'var(--size-grid007)' : '52px')};\n }\n`;\n\ninterface UseFormMethods {\n closeLayer: () => void;\n handlePreviousStep: (e: any) => void;\n handleScreenChange: (newNumber?: number) => void;\n handleSubmit: (e: SyntheticEvent) => Promise;\n nextStep: () => void;\n previousStep: () => void;\n sendForm: () => void;\n handleShowFinalScreen: () => void;\n /**\n * Flag que activa algunas funcionalidades para facilitar el desarrollo.\n */\n debug: boolean;\n /**\n * Flag que controla si el formulario está dentro de un multistep y se tiene que esperar para realizar un next step del formulario genérico.\n */\n // waitForNextStep: boolean;\n /**\n * Flag que controla si el formulario está dentro de un multistep y se tiene que esperar para realizar un previous step del formulario genérico.\n */\n waitForPreviousStep: boolean;\n // setWaitForNextStep: React.Dispatch>;\n setWaitForPreviousStep: React.Dispatch>;\n initializeForm: (\n initialFormInfo: Partial,\n initialFormData: Partial,\n skipLayerInit?: boolean\n ) => void;\n /**\n * La propiedad nextMultiStep contiene la función que (en caso de que haya un multiStep) controlará el CTA de siguiente pantalla para navegar por las subsiguientes pantallas del multiStep sin cambiar de pantalla en el formulario principal.\n */\n nextMultiStep?: () => void;\n /**\n * Al guardar una función dentro del nextMultiStep necesitamos envolverla en otra función para que React no crea que es una inicialización -> https://medium.com/swlh/how-to-store-a-function-with-the-usestate-hook-in-react-8a88dd4eede1\n */\n setNextMultiStep?: React.Dispatch void>>;\n /**\n * La propiedad previousMultiStep contiene la función que (en caso de que haya un multiStep) controlará el CTA de siguiente pantalla para navegar por las anteriores pantallas del multiStep sin cambiar de pantalla en el formulario principal.\n */\n previousMultiStep?: () => void;\n /**\n * Al guardar una función dentro del previousMultiStep necesitamos envolverla en otra función para que React no crea que es una inicialización -> https://medium.com/swlh/how-to-store-a-function-with-the-usestate-hook-in-react-8a88dd4eede1\n */\n setPreviousMultiStep?: React.Dispatch void>>;\n\n handleNextStep: (e?: any) => void;\n /**\n * Flag que controla si se muestra o no el previousStep (ej: en CitaPrevia no se muestra en el multiStep 2 de mapa)\n */\n showPreviousStep: boolean;\n setShowPreviousStep: React.Dispatch>;\n setIsFullScreen: React.Dispatch>;\n isFullScreen: boolean;\n /**\n * Flag para validacion\n */\n error: boolean;\n setError: React.Dispatch>;\n /**\n * Flags para gestionar transiciones entre pantallas\n */\n nextScreenIndex: number;\n setNextScreenIndex: React.Dispatch>;\n nextMultiStepScreenIndex: number;\n setNextMultiStepScreenIndex: React.Dispatch>;\n distanceToMove: Array;\n setDistanceToMove: React.Dispatch>>;\n moveForward: boolean;\n setMoveForward: React.Dispatch>;\n /**\n * En alguna casuística el intro no debería pasar de página, causando el cierre de la feature app. Este flag lo desactiva.\n */\n setDisableIntroNextStep: React.Dispatch>;\n /**\n * Trigger para algunos casos en que el handleClick de ScreenController no funciona bien y el next step no se activa\n * al seleccionar una opción de las disponibles en la pantalla porque no se produce ningún click.\n * EJEMPLO: Pantalla locateUser citaPosventa en la casuística que el usuario elije geolacalización\n */\n isValueSelected: boolean;\n setIsValueSelected: React.Dispatch>;\n handleAreYouSureLayer: any;\n nextStepEventEmitter: BehaviorSubject;\n}\nexport const OneFormContext = React.createContext(null);\n\nexport const useOneFormContext = (): UseFormMethods => React.useContext(OneFormContext) as UseFormMethods;\n\ninterface OneFormProviderProps {\n children: JSX.Element;\n closeLayerCallback: CloseHandleV2;\n handleAreYouSureLayer: any;\n}\n\ninterface OneFormDebug {\n debug: boolean;\n toggleDebugMode: () => void;\n}\n\ndeclare global {\n interface Window {\n OneForm: OneFormDebug;\n }\n}\n\nexport const OneFormProvider = (props: OneFormProviderProps): any => {\n const { closeLayerCallback, handleAreYouSureLayer } = props;\n const { formData, formInfo } = useSelector((state: OneFormState) => state);\n const {\n sendFormCallback,\n screenIndex,\n formEnded,\n steps,\n stepsHistory,\n nextStepCallback,\n numberOfScreens,\n lastStep,\n step,\n formSubmitted,\n notALayer,\n suggestionIsInCanaryIslands,\n } = formInfo;\n const methods = useForm();\n // const { getValues, triggerValidation } = useFormContext();\n\n const dispatch = useDispatch();\n const store = useStore();\n const [waitForPreviousStep, setWaitForPreviousStep] = useState(false);\n const [nextMultiStep, setNextMultiStep] = useState<() => void>(() => () => {});\n const [isFullScreen, setIsFullScreen] = useState(false);\n const [previousMultiStep, setPreviousMultiStep] = useState<() => void>(() => () => {});\n const [showPreviousStep, setShowPreviousStep] = useState(false);\n const [error, setError] = useState(false);\n const [nextScreenIndex, setNextScreenIndex] = useState(null);\n const [nextMultiStepScreenIndex, setNextMultiStepScreenIndex] = useState(null);\n const [distanceToMove, setDistanceToMove] = useState>([]);\n const [moveForward, setMoveForward] = useState(true);\n const oneFormService = useFeatureServices()['es:oneform-core'];\n const trackingManager = useTrackingManager();\n const [debug, setDebug] = useState(false);\n const [disableIntroNextStep, setDisableIntroNextStep] = useState(false);\n const [isValueSelected, setIsValueSelected] = useState(false);\n const [closed, setClosed] = useState(false);\n const nextStepEventEmitter: BehaviorSubject = new BehaviorSubject(false);\n const layerManager = useFeatureServices()['layer-manager'];\n const history = useFeatureServices()['s2:history'];\n const config = useFeatureAppConfig();\n const env = useFeatureAppEnvironment();\n\n useEffect(() => {\n window.OneForm = { debug, toggleDebugMode };\n // setTimeout(() => {\n // const { person } = oneFormService.get();\n // if (person) {\n // dispatch({ type: 'UPDATE_FIELDS', payload: { ...person } });\n // setObjectValues(person, methods.setValue);\n // }\n // }, 1000);\n }, []);\n\n const toggleDebugMode = () => {\n setDebug(!debug);\n window.OneForm.debug = !debug;\n };\n\n const initializeForm = (\n initialFormInfo: Partial,\n initialFormData: Partial,\n skipLayerInit?: boolean\n ) => {\n // En algunos casos al finalizar el formulario y cerrar el layer se vuelve a disparar el evento;\n if (formSubmitted || closed) {\n return;\n }\n\n dispatch({ type: 'UPDATE_FORM', payload: initialFormData });\n dispatch({ type: 'SET_FORM_INFO', payload: { ...formInfoInitialState, ...initialFormInfo } });\n dispatch({ type: 'SET_INITIAL_STEPS', payload: initialFormInfo.steps });\n setTimeout(() => {\n // Solucion al bug que se produce cuando hay un error genérico. Al resetear el estado\n // se añade el último screenIndex que había antes de producirse el error, por lo que\n // la navegación se ve alterada.\n dispatch({ type: 'SET_STEPS_HISTORY', payload: initialFormInfo.stepsHistory });\n if (!skipLayerInit) {\n trackingManager.trackFormLayerLoad();\n }\n }, 0);\n };\n\n useEffect(() => {\n if (screenIndex !== 0 && screenIndex !== null) {\n dispatch({ type: 'UPDATE_STEPS_HISTORY', payload: screenIndex });\n }\n if (screenIndex !== 2 && nextMultiStepScreenIndex !== null) setNextMultiStepScreenIndex(null);\n setTimeout(() => {\n setObjectValues(formData.fields, methods.setValue);\n }, 500);\n }, [screenIndex]);\n\n /**\n * En el journey de no compra al llegar al mapa se abre un layer. Se necesita que interactue con el next step, por lo que lo tenemos que cerrar desde aquí\n */\n const handleMapFullScreenLayer = (isNext: boolean) => {\n const layers = layerManager.getLayers();\n const layer = layers.find(\n (layer) => layer.layer.options.id === 'mapaNoCompra' || layer.layer.options.id === 'mapaNoRenovacion' || layer.layer.options.id === 'mapaLeadInPage'\n );\n\n if (layer) {\n layer.layer?.close();\n isNext ? nextStep() : previousStep();\n dispatch({ type: 'UPDATE_WAIT_FOR_NEXT_STEP', payload: false });\n setWaitForPreviousStep(false);\n }\n };\n\n const handleNextStep = async (e?: any) => {\n if (e) e.preventDefault();\n\n const { step } = store.getState().formInfo;\n\n if (step && step.isLastStep) {\n return;\n }\n const values = methods.getValues();\n\n const isValid = await methods.triggerValidation();\n const { waitForNextStep } = store.getState().formInfo;\n\n // if (isValid && suggestionIsInCanaryIslands) {\n // renderAvisoIslasCanariasLayer(store, env, layerManager);\n\n // return;\n // }\n\n if (isValid) {\n if (!moveForward) setMoveForward(true);\n setError(false);\n dispatch({ type: 'UPDATE_FIELDS', payload: values });\n\n if (\n formData.fields.formName.includes('no_compra') ||\n formData.fields.formName.includes('no_renovacion') ||\n formData.fields.formName.includes('no_renovacion') ||\n formData.fields.formName.includes('configure') \n ) {\n handleMapFullScreenLayer(true);\n }\n\n if (waitForNextStep) {\n nextMultiStep();\n } else {\n nextStep();\n }\n } else {\n setError(true);\n const keys = Object.keys(methods.errors);\n\n const errorFields: ErrorFormFields[] = keys.map((key) => {\n return { 'form field id': 'id', 'form field name': key };\n });\n\n keys.map((err) => trackingManager.trackFormErrorMessageLoad({ message: err }, errorFields));\n }\n };\n\n const nextStep = () => {\n let nextStepNumber: number;\n let nextStep: Steps;\n\n // En algunos casos según como se inicializa el form ni el screenIndex ni los steps están disponibles, por lo que hay que\n // utilizar el getState para obtener el estado actual.\n const { screenIndex, steps } = store.getState().formInfo;\n\n if (formEnded && lastStep) {\n nextStepNumber = lastStep.screenIndex;\n nextStep = lastStep;\n } else {\n nextStepNumber = nextStepCallback ? nextStepCallback() : screenIndex + 1;\n nextStep = steps[nextStepNumber];\n }\n\n handleStepChange(nextStep, nextStepNumber, true);\n };\n\n const handlePreviousStep = (e: any) => {\n e.preventDefault();\n if (moveForward) {\n setMoveForward(false);\n }\n\n if (formData.fields.formName.includes('no_compra') || formData.fields.formName.includes('no_renovacion') || formData.fields.formName.includes('lead_inpage')) {\n handleMapFullScreenLayer(false);\n }\n const values = methods.getValues();\n // Comprobar si es correcto antes de actualizar?\n // dispatch({ type: 'UPDATE_FIELDS', payload: values });\n waitForPreviousStep ? previousMultiStep() : previousStep();\n if (formEnded) dispatch({ type: 'UPDATE_FORM_ENDED', payload: false });\n };\n\n const previousStep = () => {\n // Es necesario poder sobreescribir previousStep?\n const { screenIndex, steps, stepsHistory } = store.getState().formInfo;\n\n const indexActualScreen = stepsHistory.indexOf(screenIndex);\n const newScreenIndex = stepsHistory[indexActualScreen - 1];\n const indexInSteps = steps.findIndex((step: any) => step.screenIndex === newScreenIndex);\n const previousStep = steps[indexInSteps];\n\n // Falta eliminar el último elemento de stepsHistory\n handleStepChange(previousStep, newScreenIndex, false);\n };\n\n const handleStepChange = (step: Steps, screenIndex: number, isMovingForward: boolean) => {\n handleScreenChange(screenIndex);\n dispatch({ type: 'SET_NAVIGATION_MOVING_FORWARD', payload: isMovingForward });\n setTimeout(() => {\n dispatch({ type: 'UPDATE_STEP', payload: step });\n // dispatch({ type: 'UPDATE_STEPS_HISTORY', payload: screenIndex });\n dispatch({ type: 'UPDATE_FULLSCREEN', payload: step.fullScreen });\n setIsFullScreen(step.fullScreen);\n }, TIME_FOR_TRANSFORM);\n };\n\n const handleScreenChange = (newNumber?: number) => {\n if (typeof newNumber === 'number') setNextScreenIndex(newNumber);\n dispatch({ type: 'TRIGGER_EXIT_ANIMATION', payload: true });\n setTimeout(() => {\n dispatch({ type: 'TRIGGER_EXIT_ANIMATION', payload: false });\n if (typeof newNumber === 'number') {\n dispatch({ type: 'UPDATE_SCREEN', payload: newNumber });\n }\n }, TIME_FOR_TRANSFORM);\n };\n\n const handleShowFinalScreen = () => {\n dispatch({ type: 'SHOW_FINAL_SCREEN', payload: true });\n };\n\n const closeLayer = () => {\n dispatch({ type: 'RESET_STATE' });\n setClosed(true);\n closeLayerCallback({}, {}, {});\n\n if (env.done) {\n env.done();\n }\n return;\n };\n\n const sendForm = async (): Promise => {\n return new Promise((resolve) => {\n sendFormCallback\n ? resolve(sendFormCallback())\n : setTimeout(() => {\n resolve(true);\n }, 2000);\n });\n };\n\n const handleSubmit = async (e: SyntheticEvent) => {\n e.preventDefault();\n const responseIsValid = await sendForm();\n return responseIsValid;\n };\n\n const renderAvisoCanarias = () => {\n let redirect: string;\n\n if (formData.fields.formName === 'cita-posventa') {\n redirect = 'https://www.vwcanarias.com/es/cita-previa.html';\n } else {\n redirect = 'https://cita.vwcanarias.com/';\n }\n\n return (\n \n \n \n );\n };\n\n return (\n \n \n \n {error && screenIndex !== numberOfScreens - 1 ? (\n \n \n Necesitamos esta información para seguir\n \n \n ) : null}\n \n \n );\n};\n\nexport const getDeviceType = (): string => (deviceType === 'browser' ? 'desktop' : deviceType.toLowerCase());\n\nexport const getTrackingCode = (): string => (typeof s !== 'undefined' ? (s.persCmp ? s.persCmp : null) : null);\n","module.exports = require('./lib/axios');","import React from 'react';\nimport { useStore } from 'react-redux';\nimport { Store } from 'redux';\nimport { useFeatureAppConfig, useGetBrand } from 'src/feature-app';\nimport {\n createPartner,\n createPartnerWithSearch,\n createTrackingLink,\n createTrackingProcess,\n getBaseEventInfo,\n getCarlineConfiguration,\n getCompleteConfigurationFromVicci,\n getFormAppointments,\n getMarketingConsent,\n} from 'src/feature-app/tracking-helpers';\nimport {\n emptyCarlineConfig,\n emptyConfig,\n emptyLatLongZip,\n emptyOwnership,\n emptyPersonalization,\n} from 'src/feature-app/tracking-objects';\nimport {\n ErrorFormFields,\n OffersTrackingEvent,\n OneFormTrackingManager,\n TrackingError,\n TrackingEvent,\n TrackingEventInfo,\n TrackingFilter,\n TrackingForm,\n TrackingPartner,\n TrackingProcess,\n} from 'src/feature-app/tracking-types';\nimport { DealersData, OneFormState } from 'src/types';\nimport { useFeatureServices } from './use-feature-services';\n\nconst defaultTrackingEvent: OffersTrackingEvent = {\n personalization: emptyPersonalization,\n};\n\nexport function useTrackingManager(): OneFormTrackingManager {\n const { tracking: trackingManager } = useFeatureServices();\n const store: Store = useStore();\n const config = useFeatureAppConfig();\n const brand = useGetBrand();\n\n return React.useMemo((): OneFormTrackingManager => {\n function track(action: string, event: OffersTrackingEvent): void {\n const { trackingIsDisabled } = store.getState().formInfo;\n if (trackingManager && !trackingIsDisabled) {\n trackingManager.track(action, event as TrackingEvent);\n }\n }\n\n return {\n trackFormButtonClick(eventInfo: TrackingEventInfo, dealer?: DealersData) {\n const { formName, formType } = store.getState().formData.fields;\n\n track('VWBasic_FormButton_Click', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n PrefContactChannels: undefined,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n NewsletterType: undefined,\n Questionnaire: undefined,\n ...getMarketingConsent(store),\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyConfig,\n PriceType: 'price',\n PriceTypeParameter: undefined,\n ...getCarlineConfiguration(store),\n },\n partner: createPartner(store, dealer),\n ownership: emptyOwnership,\n link: createTrackingLink(eventInfo.contentId),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormStepButtonClick(eventInfo: TrackingEventInfo) {\n const { formName, formType, pageCategory } = store.getState().formData.fields;\n\n const emptyConfigStep = { ...emptyConfig };\n delete emptyConfigStep.PriceTotalTotal;\n\n track('VWBasic_FormStepButton_Click', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n PrefContactChannels: undefined,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n NewsletterType: undefined,\n Questionnaire: undefined,\n ...getMarketingConsent(store),\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyConfigStep,\n WheelsAdditionalExternalRollingNoise: undefined,\n ...getCarlineConfiguration(store),\n },\n process: {\n Name: pageCategory,\n ...createTrackingProcess(store),\n },\n partner: createPartner(store),\n ownership: emptyOwnership,\n link: createTrackingLink(eventInfo.contentId),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormStepLoad(eventInfo: TrackingEventInfo, formInfo?: TrackingForm, processInfo?: TrackingProcess) {\n const { formName, formType, pageCategory } = store.getState().formData.fields;\n\n const baseEventInfoForLoad = { ...getBaseEventInfo(store, brand) };\n delete baseEventInfoForLoad.sectionName;\n\n const emptyConfigLoad = { ...emptyConfig };\n delete emptyConfigLoad.PriceTotalTotal;\n\n track('VWBasic_FormStep_Load', {\n ...defaultTrackingEvent,\n form: {\n ...formInfo,\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n },\n eventInfo: { ...baseEventInfoForLoad, ...eventInfo, contentLabels: undefined },\n configuration: {\n ...emptyConfigLoad,\n WheelsAdditionalExternalRollingNoise: undefined,\n ...getCarlineConfiguration(store),\n },\n user: { ...emptyLatLongZip },\n process: {\n Name: pageCategory,\n ...createTrackingProcess(store, processInfo),\n },\n partner: createPartner(store),\n ownership: emptyOwnership,\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackButtonClick(eventInfo: TrackingEventInfo, dealer?: DealersData) {\n const processInfo = createTrackingProcess(store);\n track('VWBasic_Button_Click', {\n ...defaultTrackingEvent,\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyCarlineConfig,\n ...getCarlineConfiguration(store),\n },\n partner: createPartner(store, dealer),\n ownership: emptyOwnership,\n process: processInfo,\n link: createTrackingLink(eventInfo.contentId),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n questionnaire: { QuestionAnswerSet: undefined },\n SC: {\n ResultsRecommendationPosition: undefined,\n ResultsRecommendationFirst: undefined,\n ResultsRecommendationSecond: undefined,\n },\n });\n },\n trackFormCTAClick(eventInfo: TrackingEventInfo, dealer?: DealersData) {\n const { formName, formType } = store.getState().formData.fields;\n\n track('VWBasic_FormCTA_Click', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n PrefContactChannels: undefined,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n NewsletterType: undefined,\n Questionnaire: undefined,\n ...getMarketingConsent(store),\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyConfig,\n PriceType: undefined,\n PriceTypeParameter: undefined,\n ...getCarlineConfiguration(store),\n },\n partner: createPartner(store, dealer),\n ownership: emptyOwnership,\n link: createTrackingLink(eventInfo.contentId),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormSubmissionSuccessMessageLoad(eventInfo: TrackingEventInfo, formInfo?: TrackingForm) {\n const { formName, formType, vicciData, pageCategory } = store.getState().formData.fields;\n const processInfo = createTrackingProcess(store);\n\n track('VWBasic_FormSubmissionSuccessMessage_Load', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n PrefContactChannels: undefined,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n NewsletterType: undefined,\n ErrorFormFields: undefined,\n Questionnaire: undefined,\n SourceID: undefined,\n OpportunityUID: undefined,\n CycleID: undefined,\n FormStart: false,\n LeadID: undefined,\n ...getFormAppointments(store),\n ...getMarketingConsent(store),\n ...formInfo,\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n user: { ...emptyLatLongZip },\n configuration: {\n ...emptyConfig,\n ...getCompleteConfigurationFromVicci(vicciData),\n ...getCarlineConfiguration(store),\n },\n process: { ...processInfo, StepName: 'ThankYou', Name: pageCategory },\n partner: createPartnerWithSearch(store),\n ownership: emptyOwnership,\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormLayerLoad() {\n const { formName, formType, pageCategory } = store.getState().formData.fields;\n\n const emptyConfigLoad = { ...emptyConfig };\n delete emptyConfigLoad.PriceTypeParameter;\n delete emptyConfigLoad.PriceType;\n\n track('VWBasic_FormLayer_Load', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n NewsletterType: undefined,\n CycleID: undefined,\n FormStart: true,\n },\n eventInfo: {\n ...getBaseEventInfo(store, brand),\n contentId: config.trigger ? config.trigger : undefined,\n contentLabels: undefined,\n },\n configuration: { ...emptyConfigLoad, ...getCarlineConfiguration(store) },\n process: {\n Name: pageCategory,\n ...createTrackingProcess(store),\n },\n partner: createPartner(store),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormLoad() {\n const { formName, formType, pageCategory } = store.getState().formData.fields;\n const emptyConfigLoad = { ...emptyConfig };\n\n track('VWBasic_Form_Pageload', {\n ...defaultTrackingEvent,\n environment: { featureAppIdAppVersion: process.env.VERSION },\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n FormStart: true,\n },\n eventInfo: {\n ...getBaseEventInfo(store, brand),\n contentId: config.trigger ? config.trigger : undefined,\n contentLabels: undefined,\n },\n user: { ...emptyLatLongZip },\n configuration: { ...emptyConfigLoad, ...getCarlineConfiguration(store) },\n process: {\n Name: pageCategory,\n ...createTrackingProcess(store),\n },\n partner: createPartner(store),\n });\n },\n trackFormLoadRace() {\n const { formName, formType, pageCategory } = store.getState().formData.fields;\n const emptyConfigLoad = { ...emptyConfig };\n\n track('VWBasic_Form_Load', {\n ...defaultTrackingEvent,\n environment: { featureAppIdAppVersion: process.env.VERSION },\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n FormStart: true,\n },\n eventInfo: {\n ...getBaseEventInfo(store, brand),\n contentId: config.trigger ? config.trigger : undefined,\n contentLabels: undefined,\n },\n user: { ...emptyLatLongZip },\n configuration: { ...emptyConfigLoad, ...getCarlineConfiguration(store) },\n process: {\n Name: pageCategory,\n ...createTrackingProcess(store),\n },\n partner: createPartner(store),\n });\n },\n\n trackFormErrorMessageLoad(errorInfo?: TrackingError, errorFields?: ErrorFormFields[]) {\n const { formName, formType } = store.getState().formData.fields;\n\n track('VWBasic_FormErrorMessage_Load', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n ErrorFormFields: { FieldNameandID: [...errorFields] },\n ErrorAdressValidationFields: undefined,\n },\n eventInfo: { ...getBaseEventInfo(store, brand) },\n error: { message: errorInfo.message, code: undefined, referringUrl: undefined },\n partner: createPartner(store),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormFieldClick(eventInfo: TrackingEventInfo, form: TrackingForm) {\n const { formName, formType } = store.getState().formData.fields;\n\n track('VWBasic_FormField_Click', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n ...form,\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyCarlineConfig,\n ...getCarlineConfiguration(store),\n },\n process: createTrackingProcess(store),\n partner: createPartner(store),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormFilterSelect(eventInfo: TrackingEventInfo, filter: TrackingFilter, form: TrackingForm) {\n const { formName, formType } = store.getState().formData.fields;\n\n track('VWBasic_FormFilterSelect_Click', {\n ...defaultTrackingEvent,\n form: {\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n ...form,\n },\n eventInfo: { ...getBaseEventInfo(store, brand), ...eventInfo },\n configuration: {\n ...emptyCarlineConfig,\n ...getCarlineConfiguration(store),\n },\n filter,\n process: createTrackingProcess(store),\n partner: createPartner(store),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n trackFormCloseClick(eventInfo: TrackingEventInfo, formInfo?: TrackingForm) {\n const baseEventInfoCloseClick = { ...getBaseEventInfo(store, brand) };\n delete baseEventInfoCloseClick.templateType;\n\n const partner: TrackingPartner = createPartnerWithSearch(store);\n delete partner.informationDepartment;\n\n const processInfo = createTrackingProcess(store);\n delete processInfo.StepNumber;\n const { formName, formType, vicciData } = store.getState().formData.fields;\n\n track('VWBasic_FormClose_Click', {\n ...defaultTrackingEvent,\n form: {\n ...formInfo,\n FormType: formType,\n FormName: `vw-oneform-${formName}`,\n PrefContactChannels: undefined,\n SourceID: undefined,\n ErrorFormFields: undefined,\n OpportunityUID: undefined,\n FormVersion: `vw-oneform-${formName}-${process.env.VERSION}`,\n CycleID: undefined,\n FormFields: undefined,\n ...getFormAppointments(store),\n },\n eventInfo: { ...baseEventInfoCloseClick, ...eventInfo },\n configuration: {\n ...emptyCarlineConfig,\n ...getCompleteConfigurationFromVicci(vicciData),\n ...getCarlineConfiguration(store),\n },\n process: processInfo,\n partner,\n link: createTrackingLink(eventInfo.contentId),\n environment: { featureAppIdAppVersion: process.env.VERSION },\n });\n },\n };\n }, [trackingManager]);\n}\n","export var DesignTokenSizeEnum;\n(function (DesignTokenSizeEnum) {\n DesignTokenSizeEnum[\"static0\"] = \"static0\";\n DesignTokenSizeEnum[\"static100\"] = \"static100\";\n DesignTokenSizeEnum[\"static150\"] = \"static150\";\n DesignTokenSizeEnum[\"static200\"] = \"static200\";\n DesignTokenSizeEnum[\"static250\"] = \"static250\";\n DesignTokenSizeEnum[\"static300\"] = \"static300\";\n DesignTokenSizeEnum[\"static350\"] = \"static350\";\n DesignTokenSizeEnum[\"static370\"] = \"static370\";\n DesignTokenSizeEnum[\"static400\"] = \"static400\";\n DesignTokenSizeEnum[\"static450\"] = \"static450\";\n DesignTokenSizeEnum[\"static500\"] = \"static500\";\n DesignTokenSizeEnum[\"static510\"] = \"static510\";\n DesignTokenSizeEnum[\"static515\"] = \"static515\";\n DesignTokenSizeEnum[\"static520\"] = \"static520\";\n DesignTokenSizeEnum[\"static530\"] = \"static530\";\n DesignTokenSizeEnum[\"static535\"] = \"static535\";\n DesignTokenSizeEnum[\"static550\"] = \"static550\";\n DesignTokenSizeEnum[\"static565\"] = \"static565\";\n DesignTokenSizeEnum[\"static575\"] = \"static575\";\n DesignTokenSizeEnum[\"static600\"] = \"static600\";\n DesignTokenSizeEnum[\"static625\"] = \"static625\";\n DesignTokenSizeEnum[\"static650\"] = \"static650\";\n DesignTokenSizeEnum[\"static700\"] = \"static700\";\n DesignTokenSizeEnum[\"static750\"] = \"static750\";\n DesignTokenSizeEnum[\"static800\"] = \"static800\";\n DesignTokenSizeEnum[\"static900\"] = \"static900\";\n DesignTokenSizeEnum[\"static1000\"] = \"static1000\";\n DesignTokenSizeEnum[\"static1100\"] = \"static1100\";\n DesignTokenSizeEnum[\"static1200\"] = \"static1200\";\n DesignTokenSizeEnum[\"grid001\"] = \"grid001\";\n DesignTokenSizeEnum[\"grid002\"] = \"grid002\";\n DesignTokenSizeEnum[\"grid003\"] = \"grid003\";\n DesignTokenSizeEnum[\"grid004\"] = \"grid004\";\n DesignTokenSizeEnum[\"grid005\"] = \"grid005\";\n DesignTokenSizeEnum[\"grid006\"] = \"grid006\";\n DesignTokenSizeEnum[\"grid007\"] = \"grid007\";\n DesignTokenSizeEnum[\"grid008\"] = \"grid008\";\n DesignTokenSizeEnum[\"grid009\"] = \"grid009\";\n DesignTokenSizeEnum[\"grid010\"] = \"grid010\";\n DesignTokenSizeEnum[\"grid011\"] = \"grid011\";\n DesignTokenSizeEnum[\"grid012\"] = \"grid012\";\n DesignTokenSizeEnum[\"grid013\"] = \"grid013\";\n DesignTokenSizeEnum[\"grid014\"] = \"grid014\";\n DesignTokenSizeEnum[\"grid015\"] = \"grid015\";\n DesignTokenSizeEnum[\"grid016\"] = \"grid016\";\n DesignTokenSizeEnum[\"grid017\"] = \"grid017\";\n DesignTokenSizeEnum[\"grid018\"] = \"grid018\";\n DesignTokenSizeEnum[\"grid019\"] = \"grid019\";\n DesignTokenSizeEnum[\"grid020\"] = \"grid020\";\n DesignTokenSizeEnum[\"grid021\"] = \"grid021\";\n DesignTokenSizeEnum[\"grid022\"] = \"grid022\";\n DesignTokenSizeEnum[\"grid023\"] = \"grid023\";\n DesignTokenSizeEnum[\"grid024\"] = \"grid024\";\n DesignTokenSizeEnum[\"dynamic0020\"] = \"dynamic0020\";\n DesignTokenSizeEnum[\"dynamic0040\"] = \"dynamic0040\";\n DesignTokenSizeEnum[\"dynamic0050\"] = \"dynamic0050\";\n DesignTokenSizeEnum[\"dynamic0100\"] = \"dynamic0100\";\n DesignTokenSizeEnum[\"dynamic0120\"] = \"dynamic0120\";\n DesignTokenSizeEnum[\"dynamic0130\"] = \"dynamic0130\";\n DesignTokenSizeEnum[\"dynamic0140\"] = \"dynamic0140\";\n DesignTokenSizeEnum[\"dynamic0150\"] = \"dynamic0150\";\n DesignTokenSizeEnum[\"dynamic0200\"] = \"dynamic0200\";\n DesignTokenSizeEnum[\"dynamic0250\"] = \"dynamic0250\";\n DesignTokenSizeEnum[\"dynamic0270\"] = \"dynamic0270\";\n DesignTokenSizeEnum[\"dynamic0300\"] = \"dynamic0300\";\n DesignTokenSizeEnum[\"dynamic0350\"] = \"dynamic0350\";\n DesignTokenSizeEnum[\"dynamic0450\"] = \"dynamic0450\";\n})(DesignTokenSizeEnum || (DesignTokenSizeEnum = {}));\nexport var DesignTokenFontSizes;\n(function (DesignTokenFontSizes) {\n DesignTokenFontSizes[\"size0100\"] = \"size0100\";\n DesignTokenFontSizes[\"size0150\"] = \"size0150\";\n DesignTokenFontSizes[\"size0200\"] = \"size0200\";\n DesignTokenFontSizes[\"size0250\"] = \"size0250\";\n DesignTokenFontSizes[\"size0300\"] = \"size0300\";\n DesignTokenFontSizes[\"size0350\"] = \"size0350\";\n DesignTokenFontSizes[\"size0400\"] = \"size0400\";\n DesignTokenFontSizes[\"size0450\"] = \"size0450\";\n DesignTokenFontSizes[\"size0500\"] = \"size0500\";\n DesignTokenFontSizes[\"size0550\"] = \"size0550\";\n DesignTokenFontSizes[\"size0600\"] = \"size0600\";\n})(DesignTokenFontSizes || (DesignTokenFontSizes = {}));\n","var __assign = (this && this.__assign) || function () {\n __assign = Object.assign || function(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\n t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nimport * as React from 'react';\nexport var ChevronUp = React.forwardRef(Object.assign(function (props, forwardRef) {\n var variant = props.variant || \"default\";\n if (variant === \"default\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"24\", height: \"24\", viewBox: \"0 0 24 24\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"M22.016 17.708 12.55 7.814c-.28-.298-.418-.397-.551-.397-.145 0-.31.114-.572.393l-9.443 9.897-.962-.918 9.439-9.893A2.108 2.108 0 0 1 12 6.086a2.083 2.083 0 0 1 1.517.813l9.46 9.89z\" }));\n }\n if (variant === \"large\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"48\", height: \"48\", viewBox: \"0 0 48 48\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"M44.301 35.205 25.344 15.387c-1.085-1.159-1.482-1.338-2.732-.005L3.699 35.204l-1.447-1.381 18.906-19.816A3.943 3.943 0 0 1 24 12.487a3.883 3.883 0 0 1 2.797 1.526l18.95 19.809z\" }));\n }\n if (variant === \"small\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"12\", height: \"12\", viewBox: \"0 0 12 12\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"M10.784 9.092 6.037 4.13l-.043-.046-.04.041-4.737 4.966-.962-.918 4.734-4.962A1.39 1.39 0 0 1 6 2.703a1.365 1.365 0 0 1 1.003.513l4.742 4.956z\" }));\n }\n return null;\n}, { displayName: 'ChevronUp' }));\n","var __assign = (this && this.__assign) || function () {\n __assign = Object.assign || function(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\n t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nimport * as React from 'react';\nexport var ChevronDown = React.forwardRef(Object.assign(function (props, forwardRef) {\n var variant = props.variant || \"default\";\n if (variant === \"default\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"24\", height: \"24\", viewBox: \"0 0 24 24\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"m1.984 6.19 9.465 9.893c.28.299.418.397.551.397.145 0 .31-.114.572-.392l9.443-9.898.962.918-9.439 9.893a2.108 2.108 0 0 1-1.538.81 2.083 2.083 0 0 1-1.517-.813l-9.46-9.889z\" }));\n }\n if (variant === \"large\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"48\", height: \"48\", viewBox: \"0 0 48 48\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"m3.698 12.641 18.957 19.817c1.085 1.16 1.482 1.34 2.732.006l18.912-19.822 1.447 1.381L26.84 33.839a3.943 3.943 0 0 1-2.842 1.52 3.883 3.883 0 0 1-2.797-1.526L2.252 14.023z\" }));\n }\n if (variant === \"small\") {\n return React.createElement(\"svg\", __assign({ className: props.className, \"aria-hidden\": props.ariaHidden, tabIndex: props.tabIndex, \"aria-label\": props.ariaLabel, ref: forwardRef }, (props.ariaHidden ? {} : { role: \"img\" }), { width: \"12\", height: \"12\", viewBox: \"0 0 12 12\", xmlns: \"http://www.w3.org/2000/svg\", fill: \"currentColor\" }),\n props.title && React.createElement(\"title\", null, props.title),\n React.createElement(\"path\", { d: \"m1.216 2.805 4.746 4.962.043.046.04-.041 4.738-4.966.962.918L7.01 8.686A1.39 1.39 0 0 1 6 9.195a1.365 1.365 0 0 1-1.004-.514L.255 3.725z\" }));\n }\n return null;\n}, { displayName: 'ChevronDown' }));\n","import {\n Breakpoints,\n Container,\n ContainerGutter,\n ContainerHorizontalAlignment,\n ContainerPadding,\n ContainerVerticalAlignment,\n ContainerWrap,\n CTA,\n Fieldset,\n Layout,\n LayoutRowGap,\n RadioButton,\n styled,\n Switch,\n Text,\n TextAlignment,\n TextAppearance,\n} from '@volkswagen-onehub/components-core';\nimport { CloseHandleV2, FocusLayerSizeV2, LayerManagerV2 } from '@volkswagen-onehub/layer-manager';\nimport React, { useEffect, useState } from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport { useDispatch, useStore, useSelector } from 'react-redux';\nimport { Store } from 'redux';\nimport {\n Apellido,\n AreYouSureLayer,\n Email,\n LegalesFormatoLayer,\n LssiTkmQuestions,\n MatriculaYModelo,\n Nombre,\n SelectExtended,\n Telefono,\n CarlineSelect,\n PoliticaPrivacidad,\n LastNavigation,\n} from 'src/components';\nimport {\n LayerManagerWrapper,\n useFaContent,\n useFeatureAppConfig,\n useFeatureAppEnvironment,\n useFeatureServices,\n useOneFormContext,\n weekDay_DayNumber_Month,\n weekDay_DayNumber_Month_Hour,\n} from 'src/feature-app';\nimport { VehiclesIdentityKit } from 'src/feature-service/es-oneform-core-feature-service/types';\nimport { TIME_FOR_TRANSFORM } from 'src/globals';\nimport { OneFormState, Steps } from 'src/types';\nimport { useIsComerciales } from 'src/feature-app/hooks';\nimport { getKilometrosInfo, franjaHoraria } from 'src/feature-app/InputsValues';\nimport { ArrowDown, ArrowUp, ChevronDown, ChevronUp } from '@volkswagen-onehub/icons-core';\n\nconst AllWrapper = styled.div`\n padding-top: 82px;\n`;\n\nconst TopInfoBox = styled.div`\n border: 1px solid rgba(255, 255, 255, 0.44);\n padding: 0 20px;\n width: 100%;\n @media all and (min-width: 560px) {\n padding: 0 24px;\n }\n`;\n\ntype BorderType = 'top' | 'bottom' | 'none';\n\ntype ItemProps = {\n boxItem?: boolean;\n border: BorderType;\n showEdit?: boolean;\n noPaddingTop?: boolean;\n showOperacionesMantenimiento?: boolean;\n};\n\nconst ItemWrapper = styled.div`\n width: 100%;\n text-align: left;\n border-bottom: ${(props) => (props.border === 'bottom' ? '1px solid rgba(255,255,255,0.45)' : 'none')};\n border-top: ${(props) => (props.border === 'top' ? '1px solid rgba(255,255,255,0.45)' : 'none')};\n padding: ${(props) => (props.boxItem ? '24px 0' : props.noPaddingTop ? '0 24px 44px' : '44px 24px')};\n\n .item-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: ${(props) => (props.showOperacionesMantenimiento ? '32px' : props.showEdit ? '44px' : '12px')};\n button > * {\n font-weight: ${(props) => (props.showEdit ? 'normal' : 'bold')};\n }\n &--legal {\n padding-bottom: ${(props) => (props.showEdit ? 'unset' : '31.5px')};\n }\n }\n .edit-wrapper {\n display: flex;\n flex-direction: column;\n label:first-of-type {\n margin-bottom: 23px;\n }\n }\n .input-error {\n margin-left: 0px !important;\n }\n`;\n\nconst SelectWrapper = styled.div`\n margin-bottom: 2px;\n label {\n width: 100%;\n @media all and (min-width: 560px) {\n width: 303px;\n }\n @media all and (min-width: 960px) {\n width: 320px;\n }\n }\n`;\n\nconst InputWidthWrapper = styled.div`\n width: 100%;\n margin-bottom: 2px;\n @media all and (min-width: 560px) {\n width: 303px;\n }\n @media all and (min-width: 960px) {\n width: 320px;\n }\n`;\n\nconst RadioButtonWrapper = styled.div`\n border: 1px solid white;\n padding: 20px;\n`;\n\nconst MotivoCalculadora = styled.div`\n width: 100%;\n display: flex;\n justify-content: space-between;\n`;\n\nconst isCalculadoraForm = (formName: string) => formName === 'cita-posventa-calculadora';\n\n/**\n * En calculadora se tiene que ocultar el CTA ya que el motivo no es editable.\n * @param formName\n * @returns\n */\nconst showCTAEditMotivo = (formName: string) => !isCalculadoraForm(formName);\n\n/**\n * En calculadora se tiene que ocultar el CTA ya que el taller no es editable.\n * @param formName\n * @returns\n */\nconst showCTAEditTaller = (formName: string) => formName !== 'cita-posventa-calculadora';\n\n/**\n * En calculadora se tiene que ocultar el CTA ya que el vehículo no es editable.\n * @param formName\n * @returns\n */\nconst showCTAEditVW = (formName: string) => formName !== 'cita-posventa-calculadora';\n\nconst getStepNumber = (steps: Steps[], layerName: 'isMotivoLayer' | 'isTimeLayer' | 'isTallerLayer') => {\n const index = steps.findIndex((step) => {\n if (layerName === 'isMotivoLayer' && step.name === 'Motivo') {\n return step;\n }\n if (layerName !== 'isMotivoLayer' && step.name === 'Mapa') {\n return step;\n }\n });\n return index;\n};\n\nconst formatPlateDate = (plateDate: string) => {\n if (plateDate.includes('-')) {\n return plateDate.split('-')[0];\n }\n return plateDate;\n};\n\nexport const ConfirmacionCita = () => {\n const { formData, formInfo } = useSelector((state: OneFormState) => state);\n const { userIsAuthenticated } = formInfo;\n const { fields } = formData;\n const { tmk: tmkData, lssi: lssiData, userVehicles, matricula } = formData.fields;\n const dispatch = useDispatch();\n const { handleScreenChange, setShowPreviousStep } = useOneFormContext();\n const { getValues, register, triggerValidation } = useFormContext();\n const faContent = useFaContent();\n const isComerciales = useIsComerciales();\n const { kilometrosValues, millageValues } = getKilometrosInfo(isComerciales);\n\n const [fechaHora, setFechaHora] = useState('');\n const [cocheAlTaller, setCocheAlTaller] = useState(false);\n const [cocheSustitucion, setCocheSustitucion] = useState(false);\n\n const [showEditServicios, setShowEditServicios] = useState(false);\n const [showEditSobreVW, setShowEditSobreVW] = useState(false);\n const [showEditSobreTi, setShowEditSobreTi] = useState(false);\n\n const [inputValueMatricula, setInputValueMatricula] = useState('');\n const [errorMatricula, setErrorMatricula] = useState(false);\n const [irConOtroCoche, setIrConOtroCoche] = useState(false);\n\n const [lssi, setLssi] = useState(() => (lssiData ? lssiData : null));\n const [tmk, setTmk] = useState(() => (tmkData ? tmkData : null));\n const [lssiError, setLssiError] = useState(false);\n const [tmkError, setTmkError] = useState(false);\n\n const [preselectedDealerForm, setPreselectedDealerForm] = useState(false);\n const config = useFeatureAppConfig();\n\n const useLoggedJourney = false; // De momento no es necesario usar todas las funciones del journey logueado/no logueado, tan solo el fill de los datos\n\n useEffect(() => {\n if (config.trigger === 'cita-posventa-dealer') {\n setPreselectedDealerForm(true);\n } else {\n setPreselectedDealerForm(false);\n }\n }, []);\n\n //Layer confirmacion edicion:\n\n const layerManager = useFeatureServices()['layer-manager'] as LayerManagerV2;\n const store: Store = useStore();\n const env = useFeatureAppEnvironment();\n\n const handleEdit = (layerName: 'isMotivoLayer' | 'isTimeLayer' | 'isTallerLayer') => {\n const { steps } = formInfo;\n const stepNumber = getStepNumber(steps, layerName);\n\n handleScreenChange(stepNumber);\n dispatch({ type: 'UPDATE_STEP', payload: steps[stepNumber] });\n if (layerName !== 'isMotivoLayer') {\n dispatch({ type: 'SET_SHOW_CALENDAR_ON_LOAD', payload: layerName === 'isTimeLayer' });\n dispatch({ type: 'UPDATE_MULTISTEP_SCREENINDEX', payload: 1 });\n dispatch({ type: 'SET_NAVIGATION_MOVING_FORWARD', payload: false });\n\n setTimeout(() => {\n setShowPreviousStep(false);\n }, TIME_FOR_TRANSFORM + 200);\n }\n };\n\n const handleAreYouSureLayer = (layerName: string) => {\n const layer = layerManager.openFocusLayer(renderAreYouSureLayer, { layerName }, { size: FocusLayerSizeV2.A });\n return layer;\n };\n\n const renderAreYouSureLayer = (state: any, close: CloseHandleV2