@bytebrand/fe-ui-core-autobahn 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. package/assets/autode-logo.svg +6 -6
  2. package/cards/CarCard.tsx +174 -174
  3. package/cards/CarRow.tsx +186 -182
  4. package/cards/cardParts.tsx +529 -489
  5. package/cards/index.ts +37 -35
  6. package/cards/types.ts +124 -114
  7. package/chrome/Footer.tsx +189 -189
  8. package/chrome/TopBar.tsx +405 -405
  9. package/chrome/index.ts +20 -20
  10. package/chrome/svg.d.ts +11 -11
  11. package/compat/AccardionSection/AccardionSection.styl +45 -45
  12. package/compat/AccardionSection/AccardionSection.tsx +56 -56
  13. package/compat/AccordionWidget/AccordionWidget.styl +220 -220
  14. package/compat/AccordionWidget/AccordionWidget.tsx +257 -257
  15. package/compat/AccordionWrapper/AccordionItem/AccordionItem.styl +34 -34
  16. package/compat/AccordionWrapper/AccordionItem/AccordionItem.tsx +64 -64
  17. package/compat/AccordionWrapper/AccordionWrapper.tsx +34 -34
  18. package/compat/AdvantageItem/AdvantageItem.styl +47 -47
  19. package/compat/AdvantageItem/AdvantageItem.tsx +26 -26
  20. package/compat/Alternative/DealerInfo.styl +116 -116
  21. package/compat/Alternative/DealerInfo.tsx +171 -171
  22. package/compat/Badge/Badge.styl +44 -44
  23. package/compat/Badge/Badge.tsx +25 -25
  24. package/compat/BodyTypeIcons/Audi.tsx +9 -9
  25. package/compat/BodyTypeIcons/Bmw.tsx +860 -860
  26. package/compat/BodyTypeIcons/Ford.tsx +31 -31
  27. package/compat/BodyTypeIcons/IconsConfig.tsx +44 -44
  28. package/compat/BodyTypeIcons/IconsConfigCompact.tsx +30 -30
  29. package/compat/BodyTypeIcons/Mazda.tsx +44 -44
  30. package/compat/BodyTypeIcons/MercedesBenz.tsx +38 -38
  31. package/compat/BodyTypeIcons/Opel.tsx +19 -19
  32. package/compat/BodyTypeIcons/Search.tsx +19 -19
  33. package/compat/BodyTypeIcons/SelectorCategoryCombi.tsx +68 -68
  34. package/compat/BodyTypeIcons/SelectorCategoryCompact.tsx +20 -20
  35. package/compat/BodyTypeIcons/SelectorCategoryConvertible.tsx +68 -68
  36. package/compat/BodyTypeIcons/SelectorCategoryCoupe.tsx +60 -60
  37. package/compat/BodyTypeIcons/SelectorCategoryMinibus.tsx +64 -64
  38. package/compat/BodyTypeIcons/SelectorCategorySedan.tsx +69 -69
  39. package/compat/BodyTypeIcons/SelectorCategorySuv.tsx +77 -77
  40. package/compat/BodyTypeIcons/SelectorCategoryTransporter.tsx +68 -68
  41. package/compat/BodyTypeIcons/SelectorCategoryVan.tsx +72 -72
  42. package/compat/BodyTypeIcons/Volkswagen.tsx +330 -330
  43. package/compat/BodyTypeIcons/index.ts +17 -17
  44. package/compat/Button/Button.tsx +65 -65
  45. package/compat/ButtonOld/Button.styl +65 -65
  46. package/compat/ButtonOld/Button.tsx +84 -84
  47. package/compat/Checkbox/Checkbox.styl +119 -119
  48. package/compat/Checkbox/Checkbox.tsx +151 -151
  49. package/compat/Checkbox/FormCheckbox.styl +22 -22
  50. package/compat/Checkbox/FormCheckbox.tsx +86 -86
  51. package/compat/Co2Widget/CO2Efficiency.styl +219 -219
  52. package/compat/Co2Widget/CO2Efficiency.tsx +93 -93
  53. package/compat/ContactInfo/ContactInfo.styl +22 -22
  54. package/compat/ContactInfo/ContactInfo.tsx +161 -161
  55. package/compat/ContactInfo/TemporaryTranslation.ts +11 -11
  56. package/compat/CookieModal/CookieModal.tsx +49 -49
  57. package/compat/CookieModal/Modal.tsx +43 -43
  58. package/compat/CookieModal/ModalsConfig.tsx +23 -23
  59. package/compat/CookieModal/modals/ManageCookieModal/ManageCookieModal.styl +86 -86
  60. package/compat/CookieModal/modals/ManageCookieModal/ManageCookieModal.tsx +184 -184
  61. package/compat/CookieModal/modals/PreviewCookieModal/PreviewCookieModal.styl +66 -66
  62. package/compat/CookieModal/modals/PreviewCookieModal/PreviewCookieModal.tsx +51 -51
  63. package/compat/CookieModal/modals/TestModal.tsx +7 -7
  64. package/compat/CookieModal/useModal.ts +13 -13
  65. package/compat/CustomerQuote/CustomerQuote.styl +79 -79
  66. package/compat/CustomerQuote/CustomerQuote.tsx +68 -68
  67. package/compat/CustomerQuotesSlider/CustomerQuotesSlider.styl +46 -46
  68. package/compat/CustomerQuotesSlider/CustomerQuotesSlider.tsx +79 -79
  69. package/compat/CustomerQuotesSlider/SliderArrow.tsx +20 -20
  70. package/compat/CustomerQuotesSlider/slider.global.styl +2 -2
  71. package/compat/ExpansionPanel/ExpansionPanel.tsx +68 -68
  72. package/compat/FirstInfoBlock/FirstInfoBlock.styl +33 -33
  73. package/compat/FirstInfoBlock/FirstInfoBlock.tsx +49 -49
  74. package/compat/FirstInfoBlock/FirstInfoBlockItem/FirstInfoBlockItem.styl +66 -66
  75. package/compat/FirstInfoBlock/FirstInfoBlockItem/FirstInfoBlockItem.tsx +21 -21
  76. package/compat/FormattedNumber/FormattedNumber.styl +1 -1
  77. package/compat/FormattedNumber/FormattedNumber.tsx +90 -90
  78. package/compat/IconContainer/IconContainer.styl +23 -23
  79. package/compat/IconContainer/IconContainer.tsx +34 -34
  80. package/compat/Image/Image.styl +109 -109
  81. package/compat/Image/Image.tsx +302 -302
  82. package/compat/ImageSettings/EditableOptionsTable/CustomCheckbox/CustomCheckbox.styl +7 -7
  83. package/compat/ImageSettings/EditableOptionsTable/CustomCheckbox/CustomCheckbox.tsx +30 -30
  84. package/compat/ImageSettings/EditableOptionsTable/EditableOptionsTable.styl +122 -122
  85. package/compat/ImageSettings/EditableOptionsTable/EditableOptionsTable.tsx +199 -199
  86. package/compat/ImageSettings/EditableOptionsTable/ImageIcon/ImageIcon.styl +3 -3
  87. package/compat/ImageSettings/EditableOptionsTable/ImageIcon/ImageIcon.tsx +15 -15
  88. package/compat/ImageSettings/OptionsTable/OptionsTable.styl +47 -47
  89. package/compat/ImageSettings/OptionsTable/OptionsTable.tsx +122 -122
  90. package/compat/ImageSettings/PricePlan/PricePlan.styl +63 -63
  91. package/compat/ImageSettings/PricePlan/PricePlan.tsx +32 -32
  92. package/compat/ImageSettings/index.ts +42 -42
  93. package/compat/ImagesSet/ImagesSet.styl +27 -27
  94. package/compat/ImagesSet/ImagesSet.tsx +76 -76
  95. package/compat/InfoBlockWrapper/InfoBlockWrapper.styl +41 -41
  96. package/compat/InfoBlockWrapper/InfoBlockWrapper.tsx +46 -46
  97. package/compat/Loader/Loader.styl +39 -39
  98. package/compat/Loader/Loader.tsx +32 -32
  99. package/compat/MagnifyGlass/MagnifyGlass.styl +33 -33
  100. package/compat/MagnifyGlass/MagnifyGlass.tsx +213 -213
  101. package/compat/MdAccordionGroup/MdAccordionGroup.tsx +53 -53
  102. package/compat/MdCheckbox/MdCheckbox.tsx +69 -69
  103. package/compat/MdField/MdField.tsx +100 -100
  104. package/compat/MdSelect/MdSelect.tsx +103 -103
  105. package/compat/MdSwitch/MdSwitch.tsx +29 -29
  106. package/compat/MdTabs/MdTabs.tsx +47 -47
  107. package/compat/MdTooltip/MdTooltip.tsx +31 -31
  108. package/compat/OfferDetailedSection/OfferDetailedSection.styl +31 -31
  109. package/compat/OfferDetailedSection/OfferDetailedSection.tsx +100 -100
  110. package/compat/OfferDetailedSection/partials/PanelConfig.styl +131 -131
  111. package/compat/OfferDetailedSection/partials/PanelConfig.tsx +121 -121
  112. package/compat/OfferPanel/AboAccordion/AboAccordion.styl +24 -24
  113. package/compat/OfferPanel/AboAccordion/AboAccordion.tsx +128 -128
  114. package/compat/OfferPanel/AboAccordion/AboColorOptions/AboColorOptions.styl +11 -11
  115. package/compat/OfferPanel/AboAccordion/AboColorOptions/AboColorOptions.tsx +35 -35
  116. package/compat/OfferPanel/AboAccordion/AboFaq/AboFaq.styl +20 -20
  117. package/compat/OfferPanel/AboAccordion/AboFaq/AboFaq.tsx +25 -25
  118. package/compat/OfferPanel/AboAccordion/AboIncludedServices/AboIncludedServices.styl +13 -13
  119. package/compat/OfferPanel/AboAccordion/AboIncludedServices/AboIncludedServices.tsx +39 -39
  120. package/compat/OfferPanel/MuiOfferPeriod/MuiOfferPeriod.tsx +42 -42
  121. package/compat/OfferPanel/OfferCheckboxGroup/CheckboxContainer.tsx +140 -140
  122. package/compat/OfferPanel/OfferCheckboxGroup/OfferCheckboxGroup.styl +144 -144
  123. package/compat/OfferPanel/OfferCheckboxGroup/OfferCheckboxGroup.tsx +23 -23
  124. package/compat/OfferPanel/OfferPanel.styl +193 -193
  125. package/compat/OfferPanel/OfferPanel.tsx +81 -81
  126. package/compat/OfferPanel/OfferPeriod/OfferPeriod.styl +24 -24
  127. package/compat/OfferPanel/OfferPeriod/OfferPeriod.tsx +45 -45
  128. package/compat/OfferPanel/RangeGroup/RangeGroup.tsx +39 -39
  129. package/compat/OfferRequestButtonWrapper/OfferRequestButtonWrapper.styl +119 -119
  130. package/compat/OfferRequestButtonWrapper/OfferRequestButtonWrapper.styled.tsx +33 -33
  131. package/compat/OfferRequestButtonWrapper/OfferRequestButtonWrapper.tsx +122 -122
  132. package/compat/PriceRating/PriceRating.styl +47 -47
  133. package/compat/PriceRating/PriceRating.tsx +64 -64
  134. package/compat/PriceRatingDetailed/PriceRatingDetailed.styl +120 -120
  135. package/compat/PriceRatingDetailed/PriceRatingDetailed.tsx +191 -191
  136. package/compat/PricingToolBlock/PricingTool.styl +6 -6
  137. package/compat/PricingToolBlock/PricingTool.tsx +29 -29
  138. package/compat/Radio/Radio.styl +115 -115
  139. package/compat/Radio/Radio.tsx +141 -141
  140. package/compat/Radio/RadioGroup.styl +5 -5
  141. package/compat/Radio/RadioGroup.tsx +65 -65
  142. package/compat/Range/Range.tsx +79 -79
  143. package/compat/RateSearchValue/RateSearchValue.styl +22 -22
  144. package/compat/RateSearchValue/RateSearchValue.tsx +55 -55
  145. package/compat/RateSearchWidget/RateSearchWidget.styl +106 -106
  146. package/compat/RateSearchWidget/RateSearchWidget.tsx +163 -163
  147. package/compat/ServiceBlockItem/ServiceBlockItem.styl +47 -47
  148. package/compat/ServiceBlockItem/ServiceBlockItem.tsx +25 -25
  149. package/compat/SkeletonItem/SkeletonItem.styl +80 -80
  150. package/compat/SkeletonItem/SkeletonItem.tsx +80 -80
  151. package/compat/StarButton/StarButton.styl +39 -39
  152. package/compat/StarButton/StarButton.tsx +31 -31
  153. package/compat/TabPanel/TabPanel.tsx +28 -28
  154. package/compat/TimePicker/TimePicker.styl +22 -22
  155. package/compat/TimePicker/TimePicker.tsx +156 -156
  156. package/compat/Tooltip/Tooltip.styl +117 -117
  157. package/compat/Tooltip/Tooltip.tsx +63 -63
  158. package/compat/Usp/Usp.styl +78 -78
  159. package/compat/Usp/Usp.tsx +30 -30
  160. package/compat/Usp/uspTranslate.ts +12 -12
  161. package/compat/VehicleDetailedSidebar/VehicleDetailedSidebar.styl +36 -36
  162. package/compat/VehicleDetailedSidebar/VehicleDetailedSidebar.tsx +178 -178
  163. package/compat/VehicleDetailedSidebar/partials/Price.styl +27 -27
  164. package/compat/VehicleDetailedSidebar/partials/Price.tsx +41 -41
  165. package/compat/VehicleDetailedSidebar/partials/PriceContent.styl +123 -123
  166. package/compat/VehicleDetailedSidebar/partials/PriceContent.tsx +128 -128
  167. package/compat/VehicleDetailedSidebar/partials/Properties.styl +58 -58
  168. package/compat/VehicleDetailedSidebar/partials/Properties.tsx +155 -155
  169. package/compat/VehicleDetailedSidebar/partials/Title.styl +35 -35
  170. package/compat/VehicleDetailedSidebar/partials/Title.tsx +33 -33
  171. package/compat/VehicleDetailedSlider/VehicleDetailedSlider.styl +146 -146
  172. package/compat/VehicleDetailedSlider/VehicleDetailedSlider.tsx +382 -382
  173. package/compat/VehicleDetailedSlider/partials/MobileStast.tsx +61 -61
  174. package/compat/VehicleDetailedSlider/partials/MobileStats.styl +71 -71
  175. package/compat/VehicleDetailedSlider/partials/PriceData.styl +50 -50
  176. package/compat/VehicleDetailedSlider/partials/PriceData.tsx +67 -67
  177. package/compat/VehicleDetailedSlider/partials/Stats.styl +80 -80
  178. package/compat/VehicleDetailedSlider/partials/Stats.tsx +62 -62
  179. package/compat/VehicleDetailedSlider/partials/Title.styl +44 -44
  180. package/compat/VehicleDetailedSlider/partials/Title.tsx +36 -36
  181. package/compat/VehicleFormattedPrice/VehicleFormattedPrice.styl +148 -148
  182. package/compat/VehicleFormattedPrice/VehicleFormattedPrice.tsx +163 -163
  183. package/compat/VehicleSlider/VehicleSlider.styl +62 -62
  184. package/compat/VehicleSlider/VehicleSlider.tsx +125 -125
  185. package/compat/VehicleSlider/VehicleSliderForSRL.tsx +175 -175
  186. package/compat/VehicleSmallCard/SeoText/SeoText.styl +8 -8
  187. package/compat/VehicleSmallCard/SeoText/SeoText.tsx +16 -16
  188. package/compat/VehicleSmallCard/VehicleData/VechiclePriceItem/VechiclePriceItem.styl +204 -204
  189. package/compat/VehicleSmallCard/VehicleData/VechiclePriceItem/VechiclePriceItem.tsx +199 -199
  190. package/compat/VehicleSmallCard/VehicleData/VehicleInfo/VehicleInfo.styl +273 -273
  191. package/compat/VehicleSmallCard/VehicleData/VehicleInfo/VehicleInfo.tsx +179 -179
  192. package/compat/VehicleSmallCard/VehicleData/VehiclePrice/VehiclePrice.styl +165 -165
  193. package/compat/VehicleSmallCard/VehicleData/VehiclePrice/VehiclePrice.tsx +299 -299
  194. package/compat/VehicleSmallCard/VehicleData/VehicleProperty/VehicleProperty.styl +32 -32
  195. package/compat/VehicleSmallCard/VehicleData/VehicleProperty/VehicleProperty.tsx +35 -35
  196. package/compat/VehicleSmallCard/VehicleData/VehicleTitle/VehicleTitle.styl +135 -135
  197. package/compat/VehicleSmallCard/VehicleData/VehicleTitle/VehicleTitle.tsx +91 -91
  198. package/compat/VehicleSmallCard/VehicleSmallCard.styl +309 -309
  199. package/compat/VehicleSmallCard/VehicleSmallCard.tsx +448 -448
  200. package/compat/index.ts +77 -77
  201. package/compat/legacy-theme/mixins.styl +93 -93
  202. package/compat/legacy-theme/priceReviewColors.styl +12 -12
  203. package/compat/legacy-theme/slider.global.styl +5 -5
  204. package/compat/legacy-theme/theme.styl +136 -136
  205. package/compat/withLabel/withLabel.styl +33 -33
  206. package/compat/withLabel/withLabel.tsx +44 -44
  207. package/compat/withStats/withStats.styl +174 -174
  208. package/compat/withStats/withStats.tsx +238 -238
  209. package/constants/RateSearchWidget.ts +15 -15
  210. package/constants/Search.ts +290 -290
  211. package/constants/SearchWidget.ts +108 -108
  212. package/constants/app.ts +223 -223
  213. package/constants/common.ts +127 -127
  214. package/constants/core.ts +131 -131
  215. package/constants/highlights.ts +165 -165
  216. package/constants/price.ts +9 -9
  217. package/constants/selectors.ts +38 -38
  218. package/constants.ts +91 -91
  219. package/data/DataTransformers.ts +88 -88
  220. package/data/fieldMapping.ts +364 -342
  221. package/data/toAutobahnCar.ts +455 -442
  222. package/iconsvg/IconSVG.tsx +30 -30
  223. package/iconsvg/IconSVGConfig.tsx +768 -768
  224. package/iconsvg/SVG/AboPartner.tsx +16 -16
  225. package/iconsvg/SVG/ArrowQuotes.tsx +22 -22
  226. package/iconsvg/SVG/CloseIcon.tsx +17 -17
  227. package/iconsvg/SVG/CloseIconSelect.tsx +18 -18
  228. package/iconsvg/SVG/ClosedLockIcon.tsx +18 -18
  229. package/iconsvg/SVG/DealerCheckIcon.tsx +18 -18
  230. package/iconsvg/SVG/DealerPopoverMail.tsx +21 -21
  231. package/iconsvg/SVG/DealerPopoverPhone.tsx +21 -21
  232. package/iconsvg/SVG/GrayPhoneIcon.tsx +22 -22
  233. package/iconsvg/SVG/InternetIcon.tsx +18 -18
  234. package/iconsvg/SVG/WhiteEnvelopeIcon.tsx +21 -21
  235. package/iconsvg/SVG/bodyType/Cabrio.tsx +23 -23
  236. package/iconsvg/SVG/bodyType/Coupe.tsx +22 -22
  237. package/iconsvg/SVG/bodyType/Minibus.tsx +22 -22
  238. package/iconsvg/SVG/bodyType/Other.tsx +25 -25
  239. package/iconsvg/SVG/bodyType/Sedan.tsx +22 -22
  240. package/iconsvg/SVG/bodyType/SelectorCategoryCombi.tsx +68 -68
  241. package/iconsvg/SVG/bodyType/SelectorCategoryCompact.tsx +20 -20
  242. package/iconsvg/SVG/bodyType/SelectorCategoryConvertible.tsx +68 -68
  243. package/iconsvg/SVG/bodyType/SelectorCategoryCoupe.tsx +60 -60
  244. package/iconsvg/SVG/bodyType/SelectorCategoryMinibus.tsx +64 -64
  245. package/iconsvg/SVG/bodyType/SelectorCategoryOther.tsx +60 -60
  246. package/iconsvg/SVG/bodyType/SelectorCategorySedan.tsx +69 -69
  247. package/iconsvg/SVG/bodyType/SelectorCategorySuv.tsx +77 -77
  248. package/iconsvg/SVG/bodyType/SelectorCategoryTransporter.tsx +68 -68
  249. package/iconsvg/SVG/bodyType/SelectorCategoryVan.tsx +72 -72
  250. package/iconsvg/SVG/bodyType/Small.tsx +23 -23
  251. package/iconsvg/SVG/bodyType/Suv.tsx +23 -23
  252. package/iconsvg/SVG/bodyType/Van.tsx +23 -23
  253. package/iconsvg/SVG/bodyType/Wagon.tsx +23 -23
  254. package/iconsvg/SVG/common/AddIcon.tsx +16 -16
  255. package/iconsvg/SVG/common/AddPlus.tsx +16 -16
  256. package/iconsvg/SVG/common/AddressDashboard.tsx +29 -29
  257. package/iconsvg/SVG/common/AddressIcon.tsx +20 -20
  258. package/iconsvg/SVG/common/ArrowDetailedAccordionBlue.tsx +26 -26
  259. package/iconsvg/SVG/common/ArrowDownBlue.tsx +21 -21
  260. package/iconsvg/SVG/common/ArrowSelect.tsx +23 -23
  261. package/iconsvg/SVG/common/ArrowStepDown.tsx +18 -18
  262. package/iconsvg/SVG/common/Autocheck.tsx +19 -19
  263. package/iconsvg/SVG/common/AutodeLogo.tsx +36 -36
  264. package/iconsvg/SVG/common/Avatar.tsx +17 -17
  265. package/iconsvg/SVG/common/BellGray.tsx +19 -19
  266. package/iconsvg/SVG/common/BigInfoTransparent.tsx +13 -13
  267. package/iconsvg/SVG/common/Browse.tsx +20 -20
  268. package/iconsvg/SVG/common/Calendar.tsx +24 -24
  269. package/iconsvg/SVG/common/CallbackDashboard.tsx +30 -30
  270. package/iconsvg/SVG/common/Camera.tsx +17 -17
  271. package/iconsvg/SVG/common/Car.tsx +16 -16
  272. package/iconsvg/SVG/common/CarBody.tsx +19 -19
  273. package/iconsvg/SVG/common/CarFront.tsx +43 -43
  274. package/iconsvg/SVG/common/CarInspectionCheck.tsx +21 -21
  275. package/iconsvg/SVG/common/CarInspectionScheme0.tsx +32 -32
  276. package/iconsvg/SVG/common/CarInspectionScheme1.tsx +53 -53
  277. package/iconsvg/SVG/common/CarInspectionScheme2.tsx +52 -52
  278. package/iconsvg/SVG/common/CarInspectionScheme3.tsx +32 -32
  279. package/iconsvg/SVG/common/CarInspectionScheme4.tsx +32 -32
  280. package/iconsvg/SVG/common/CarInspectionScheme5.tsx +32 -32
  281. package/iconsvg/SVG/common/CarInspectionScheme6.tsx +32 -32
  282. package/iconsvg/SVG/common/CarInspectionSchemeGeneral copy.tsx +24 -24
  283. package/iconsvg/SVG/common/CarInspectionSchemeGeneral.tsx +24 -24
  284. package/iconsvg/SVG/common/CheckBlue.tsx +18 -18
  285. package/iconsvg/SVG/common/CheckGreen.tsx +22 -22
  286. package/iconsvg/SVG/common/CheckMark.tsx +16 -16
  287. package/iconsvg/SVG/common/CheckWhite.tsx +19 -19
  288. package/iconsvg/SVG/common/Chevron.tsx +17 -17
  289. package/iconsvg/SVG/common/CircledCheckmark.tsx +25 -25
  290. package/iconsvg/SVG/common/Clock.tsx +18 -18
  291. package/iconsvg/SVG/common/Close.tsx +19 -19
  292. package/iconsvg/SVG/common/CloseGrey.tsx +22 -22
  293. package/iconsvg/SVG/common/ContactEmail.tsx +21 -21
  294. package/iconsvg/SVG/common/ContactPhone.tsx +28 -28
  295. package/iconsvg/SVG/common/CopyIcon copy.tsx +22 -22
  296. package/iconsvg/SVG/common/CopyIcon.tsx +22 -22
  297. package/iconsvg/SVG/common/CopyIconForDealer.tsx +21 -21
  298. package/iconsvg/SVG/common/DashboardIcon.tsx +20 -20
  299. package/iconsvg/SVG/common/DashboardQuestionMark.tsx +20 -20
  300. package/iconsvg/SVG/common/DealersIcon.tsx +20 -20
  301. package/iconsvg/SVG/common/DeleteCircle.tsx +31 -31
  302. package/iconsvg/SVG/common/DeleteV1Icon.tsx +18 -18
  303. package/iconsvg/SVG/common/DeliveryDashboard.tsx +25 -25
  304. package/iconsvg/SVG/common/DeliveryMail.tsx +24 -24
  305. package/iconsvg/SVG/common/Discount100De.tsx +18 -18
  306. package/iconsvg/SVG/common/Discount100En.tsx +19 -19
  307. package/iconsvg/SVG/common/Discount66De.tsx +28 -28
  308. package/iconsvg/SVG/common/Discount66En.tsx +20 -20
  309. package/iconsvg/SVG/common/DoneIcon.tsx +18 -18
  310. package/iconsvg/SVG/common/EditCircle.tsx +32 -32
  311. package/iconsvg/SVG/common/EditPriceIcon.tsx +20 -20
  312. package/iconsvg/SVG/common/EuroCurrency.tsx +18 -18
  313. package/iconsvg/SVG/common/Export.tsx +20 -20
  314. package/iconsvg/SVG/common/Eye.tsx +17 -17
  315. package/iconsvg/SVG/common/EyeCatch.tsx +19 -19
  316. package/iconsvg/SVG/common/FavoritesIcon.tsx +20 -20
  317. package/iconsvg/SVG/common/FilterRange.tsx +16 -16
  318. package/iconsvg/SVG/common/FilterToolBlack.tsx +23 -23
  319. package/iconsvg/SVG/common/FlagDe.tsx +21 -21
  320. package/iconsvg/SVG/common/FlagEn.tsx +43 -43
  321. package/iconsvg/SVG/common/GrayEnvelopeIcon.tsx +19 -19
  322. package/iconsvg/SVG/common/HamburgerMenuIcon.tsx +18 -18
  323. package/iconsvg/SVG/common/HandingOverDashboard.tsx +32 -32
  324. package/iconsvg/SVG/common/ImageSettingsIcon.tsx +20 -20
  325. package/iconsvg/SVG/common/Info.tsx +16 -16
  326. package/iconsvg/SVG/common/InfoIcon.tsx +17 -17
  327. package/iconsvg/SVG/common/InfoTransparent.tsx +18 -18
  328. package/iconsvg/SVG/common/LogoutIcon.tsx +20 -20
  329. package/iconsvg/SVG/common/MagnifyingGlass.tsx +31 -31
  330. package/iconsvg/SVG/common/MenuArrow.tsx +16 -16
  331. package/iconsvg/SVG/common/MenuGrey.tsx +22 -22
  332. package/iconsvg/SVG/common/MobileDeLogo.tsx +108 -108
  333. package/iconsvg/SVG/common/MyOrderIcon.tsx +20 -20
  334. package/iconsvg/SVG/common/MyVehiclesIcon.tsx +20 -20
  335. package/iconsvg/SVG/common/NewFlagDe.tsx +25 -25
  336. package/iconsvg/SVG/common/NewFlagEn.tsx +34 -34
  337. package/iconsvg/SVG/common/OrderReceivedDashboard.tsx +27 -27
  338. package/iconsvg/SVG/common/Package.tsx +30 -30
  339. package/iconsvg/SVG/common/Phone.tsx +18 -18
  340. package/iconsvg/SVG/common/PhoneGrey.tsx +22 -22
  341. package/iconsvg/SVG/common/PickupDashboard.tsx +30 -30
  342. package/iconsvg/SVG/common/Picture.tsx +24 -24
  343. package/iconsvg/SVG/common/Pictures.tsx +32 -32
  344. package/iconsvg/SVG/common/Plus.tsx +16 -16
  345. package/iconsvg/SVG/common/PlusNew.tsx +16 -16
  346. package/iconsvg/SVG/common/PreparationDashboard.tsx +29 -29
  347. package/iconsvg/SVG/common/ProfileDashboard.tsx +24 -24
  348. package/iconsvg/SVG/common/ProfileIcon.tsx +17 -17
  349. package/iconsvg/SVG/common/Question.tsx +19 -19
  350. package/iconsvg/SVG/common/QuestionBold.tsx +25 -25
  351. package/iconsvg/SVG/common/RegistrationDashboard.tsx +31 -31
  352. package/iconsvg/SVG/common/SavedSearchsIcon.tsx +20 -20
  353. package/iconsvg/SVG/common/Search.tsx +19 -19
  354. package/iconsvg/SVG/common/SearchGrey.tsx +22 -22
  355. package/iconsvg/SVG/common/SettingPenIcon.tsx +20 -20
  356. package/iconsvg/SVG/common/Share.tsx +16 -16
  357. package/iconsvg/SVG/common/ShoppingCart.tsx +18 -18
  358. package/iconsvg/SVG/common/SliderArrow.tsx +21 -21
  359. package/iconsvg/SVG/common/SliderEye.tsx +17 -17
  360. package/iconsvg/SVG/common/SortUpDownArrows.tsx +18 -18
  361. package/iconsvg/SVG/common/Speedometer.tsx +23 -23
  362. package/iconsvg/SVG/common/Star.tsx +20 -20
  363. package/iconsvg/SVG/common/StarNew.tsx +16 -16
  364. package/iconsvg/SVG/common/StarOutline.tsx +20 -20
  365. package/iconsvg/SVG/common/StarRoundedCorners.tsx +18 -18
  366. package/iconsvg/SVG/common/Stats.tsx +17 -17
  367. package/iconsvg/SVG/common/Step1.tsx +21 -21
  368. package/iconsvg/SVG/common/Step2.tsx +20 -20
  369. package/iconsvg/SVG/common/Step3.tsx +21 -21
  370. package/iconsvg/SVG/common/SupportCallbackIcon.tsx +20 -20
  371. package/iconsvg/SVG/common/Telephone.tsx +22 -22
  372. package/iconsvg/SVG/common/Time.tsx +17 -17
  373. package/iconsvg/SVG/common/Timetable.tsx +18 -18
  374. package/iconsvg/SVG/common/Trash.tsx +22 -22
  375. package/iconsvg/SVG/common/TrashRed.tsx +23 -23
  376. package/iconsvg/SVG/common/Upload.tsx +17 -17
  377. package/iconsvg/SVG/common/UserGrey.tsx +22 -22
  378. package/iconsvg/SVG/common/UserProfileIcon.tsx +20 -20
  379. package/iconsvg/SVG/common/ValidateFailure.tsx +21 -21
  380. package/iconsvg/SVG/common/ValidateSuccess.tsx +21 -21
  381. package/iconsvg/SVG/common/WarningTriangle.tsx +20 -20
  382. package/iconsvg/SVG/common/WhiteArrowUp.tsx +21 -21
  383. package/iconsvg/SVG/common/WhiteKey.tsx +21 -21
  384. package/iconsvg/SVG/common/WhitePeople.tsx +23 -23
  385. package/iconsvg/SVG/common/WhiteTick.tsx +19 -19
  386. package/iconsvg/SVG/flags/AT.tsx +19 -19
  387. package/iconsvg/SVG/flags/BE.tsx +20 -20
  388. package/iconsvg/SVG/flags/BG.tsx +20 -20
  389. package/iconsvg/SVG/flags/CH.tsx +22 -22
  390. package/iconsvg/SVG/flags/CZ.tsx +18 -18
  391. package/iconsvg/SVG/flags/DE.tsx +18 -18
  392. package/iconsvg/SVG/flags/DK.tsx +18 -18
  393. package/iconsvg/SVG/flags/ES.tsx +2585 -2585
  394. package/iconsvg/SVG/flags/FI.tsx +18 -18
  395. package/iconsvg/SVG/flags/FR.tsx +20 -20
  396. package/iconsvg/SVG/flags/GB.tsx +26 -26
  397. package/iconsvg/SVG/flags/HR.tsx +135 -135
  398. package/iconsvg/SVG/flags/HU.tsx +20 -20
  399. package/iconsvg/SVG/flags/IT.tsx +20 -20
  400. package/iconsvg/SVG/flags/LI.tsx +106 -106
  401. package/iconsvg/SVG/flags/LU.tsx +18 -18
  402. package/iconsvg/SVG/flags/NL.tsx +18 -18
  403. package/iconsvg/SVG/flags/NO.tsx +20 -20
  404. package/iconsvg/SVG/flags/PL.tsx +19 -19
  405. package/iconsvg/SVG/flags/RO.tsx +20 -20
  406. package/iconsvg/SVG/flags/RU.tsx +20 -20
  407. package/iconsvg/SVG/flags/SE.tsx +20 -20
  408. package/iconsvg/SVG/flags/SI.tsx +54 -54
  409. package/iconsvg/SVG/flags/SK.tsx +34 -34
  410. package/iconsvg/SVG/flags/UA.tsx +19 -19
  411. package/iconsvg/SVG/infoBlocks/14DaysReturnPolicy.tsx +18 -18
  412. package/iconsvg/SVG/infoBlocks/AlertInfo.tsx +19 -19
  413. package/iconsvg/SVG/infoBlocks/Autocheck.tsx +19 -19
  414. package/iconsvg/SVG/infoBlocks/CheckTheStory.tsx +22 -22
  415. package/iconsvg/SVG/infoBlocks/CustomerServiceWhite.tsx +16 -16
  416. package/iconsvg/SVG/infoBlocks/Guarantee.tsx +16 -16
  417. package/iconsvg/SVG/infoBlocks/OrderWhite.tsx +13 -13
  418. package/iconsvg/SVG/infoBlocks/PriceGuarantee.tsx +19 -19
  419. package/iconsvg/SVG/infoBlocks/PriceGuaranteeWhite.tsx +17 -17
  420. package/iconsvg/SVG/infoBlocks/TransportAndDelivery.tsx +21 -21
  421. package/iconsvg/SVG/infoBlocks/Warranty.tsx +23 -23
  422. package/iconsvg/SVG/popower/Mail.tsx +18 -18
  423. package/iconsvg/SVG/popower/Phone.tsx +19 -19
  424. package/iconsvg/SVG/popower/Schedule.tsx +18 -18
  425. package/iconsvg/SVG/searchWidgets/drive/AAllWheelDrive.tsx +26 -26
  426. package/iconsvg/SVG/searchWidgets/drive/AllWheelDrive.tsx +26 -26
  427. package/iconsvg/SVG/searchWidgets/drive/FrontWheelDrive.tsx +25 -25
  428. package/iconsvg/SVG/searchWidgets/drive/OtherWheelDrive.tsx +26 -26
  429. package/iconsvg/SVG/searchWidgets/drive/RearWheelDrive.tsx +25 -25
  430. package/iconsvg/SVG/searchWidgets/fuel/FuelDiesel.tsx +18 -18
  431. package/iconsvg/SVG/searchWidgets/fuel/FuelElectrical.tsx +19 -19
  432. package/iconsvg/SVG/searchWidgets/fuel/FuelElectricalDiesel.tsx +34 -34
  433. package/iconsvg/SVG/searchWidgets/fuel/FuelElectricalPetrol.tsx +20 -20
  434. package/iconsvg/SVG/searchWidgets/fuel/FuelEthanol.tsx +53 -53
  435. package/iconsvg/SVG/searchWidgets/fuel/FuelHydrogen.tsx +24 -24
  436. package/iconsvg/SVG/searchWidgets/fuel/FuelLpg.tsx +24 -24
  437. package/iconsvg/SVG/searchWidgets/fuel/FuelNaturalGas.tsx +23 -23
  438. package/iconsvg/SVG/searchWidgets/fuel/FuelOther.tsx +28 -28
  439. package/iconsvg/SVG/searchWidgets/fuel/FuelPetrol.tsx +18 -18
  440. package/iconsvg/SVG/settings/Account.tsx +17 -17
  441. package/iconsvg/SVG/settings/DataUsage.tsx +17 -17
  442. package/iconsvg/SVG/settings/MarketResearch.tsx +17 -17
  443. package/iconsvg/SVG/settings/Newsletter.tsx +17 -17
  444. package/iconsvg/SVG/settings/RemoveEye.tsx +17 -17
  445. package/iconsvg/SVG/settings/RemoveEyeOff.tsx +17 -17
  446. package/iconsvg/SVG/settings/Security.tsx +17 -17
  447. package/iconsvg/SVG/settings/Warning.tsx +17 -17
  448. package/iconsvg/SVG/slider/360.tsx +23 -23
  449. package/iconsvg/SVG/slider/360New.tsx +20 -20
  450. package/iconsvg/SVG/slider/Checked.tsx +19 -19
  451. package/iconsvg/SVG/slider/DiscountRibbon.tsx +51 -51
  452. package/iconsvg/SVG/slider/DiscountRibbonMobile.tsx +47 -47
  453. package/iconsvg/SVG/slider/DiscountRibbonNew.tsx +29 -29
  454. package/iconsvg/SVG/slider/Easy.tsx +19 -19
  455. package/iconsvg/SVG/slider/Fullscreen.tsx +16 -16
  456. package/iconsvg/SVG/slider/FullscreenWindow.tsx +23 -23
  457. package/iconsvg/SVG/slider/Safe.tsx +19 -19
  458. package/iconsvg/SVG/slider/ToBuy.tsx +19 -19
  459. package/iconsvg/SVG/slider/YoutubeButton.tsx +26 -26
  460. package/iconsvg/SVG/slider/ZoomIn.tsx +21 -21
  461. package/iconsvg/SVG/slider/ZoomOut.tsx +21 -21
  462. package/iconsvg/SVG/social/AndroidLogo.tsx +18 -18
  463. package/iconsvg/SVG/social/Apple.tsx +19 -19
  464. package/iconsvg/SVG/social/FacebookF.tsx +19 -19
  465. package/iconsvg/SVG/social/GooglePlusG.tsx +19 -19
  466. package/iconsvg/SVG/social/Instagram.tsx +17 -17
  467. package/iconsvg/SVG/social/Pinterest.tsx +19 -19
  468. package/iconsvg/SVG/social/SharingInterface.tsx +21 -21
  469. package/iconsvg/SVG/social/Twitter.tsx +19 -19
  470. package/iconsvg/SVG/social/Youtube.tsx +19 -19
  471. package/iconsvg/SVG/vehicle/AboIcon.tsx +11 -11
  472. package/iconsvg/SVG/vehicle/Abs.tsx +24 -24
  473. package/iconsvg/SVG/vehicle/AirCond.tsx +34 -34
  474. package/iconsvg/SVG/vehicle/Airbag.tsx +21 -21
  475. package/iconsvg/SVG/vehicle/AuxiliaryHeating.tsx +23 -23
  476. package/iconsvg/SVG/vehicle/Bluetooth.tsx +22 -22
  477. package/iconsvg/SVG/vehicle/BuyIcon.tsx +15 -15
  478. package/iconsvg/SVG/vehicle/CarAvailability.tsx +22 -22
  479. package/iconsvg/SVG/vehicle/CarInspectionCheck.tsx +21 -21
  480. package/iconsvg/SVG/vehicle/CarInspectionCross.tsx +21 -21
  481. package/iconsvg/SVG/vehicle/CheckoutChecked.tsx +15 -15
  482. package/iconsvg/SVG/vehicle/Co2.tsx +24 -24
  483. package/iconsvg/SVG/vehicle/CruiseControl.tsx +25 -25
  484. package/iconsvg/SVG/vehicle/Date.tsx +21 -21
  485. package/iconsvg/SVG/vehicle/Delivery.tsx +12 -12
  486. package/iconsvg/SVG/vehicle/Diesel.tsx +28 -28
  487. package/iconsvg/SVG/vehicle/Display.tsx +25 -25
  488. package/iconsvg/SVG/vehicle/Done.tsx +11 -11
  489. package/iconsvg/SVG/vehicle/Door.tsx +19 -19
  490. package/iconsvg/SVG/vehicle/DoubleDone.tsx +18 -18
  491. package/iconsvg/SVG/vehicle/EditIcon.tsx +11 -11
  492. package/iconsvg/SVG/vehicle/EmergencyBrakeAssistant.tsx +27 -27
  493. package/iconsvg/SVG/vehicle/Eps.tsx +24 -24
  494. package/iconsvg/SVG/vehicle/Esp.tsx +24 -24
  495. package/iconsvg/SVG/vehicle/FinancingIcon.tsx +20 -20
  496. package/iconsvg/SVG/vehicle/FuelConsumption.tsx +20 -20
  497. package/iconsvg/SVG/vehicle/Fueling.tsx +22 -22
  498. package/iconsvg/SVG/vehicle/FullDrive.tsx +24 -24
  499. package/iconsvg/SVG/vehicle/GasElectric.tsx +28 -28
  500. package/iconsvg/SVG/vehicle/HandsFreePhoneSystem.tsx +24 -24
  501. package/iconsvg/SVG/vehicle/Kw.tsx +23 -23
  502. package/iconsvg/SVG/vehicle/LastCrawledAt.tsx +22 -22
  503. package/iconsvg/SVG/vehicle/LeasingIcon.tsx +14 -14
  504. package/iconsvg/SVG/vehicle/Led.tsx +24 -24
  505. package/iconsvg/SVG/vehicle/LightSensor.tsx +22 -22
  506. package/iconsvg/SVG/vehicle/LinkAlternative.tsx +15 -15
  507. package/iconsvg/SVG/vehicle/Location.tsx +17 -17
  508. package/iconsvg/SVG/vehicle/MinusIcon.tsx +11 -11
  509. package/iconsvg/SVG/vehicle/Mirror.tsx +19 -19
  510. package/iconsvg/SVG/vehicle/Navigation.tsx +27 -27
  511. package/iconsvg/SVG/vehicle/NewCar.tsx +21 -21
  512. package/iconsvg/SVG/vehicle/NoImage.tsx +17 -17
  513. package/iconsvg/SVG/vehicle/Owner.tsx +18 -18
  514. package/iconsvg/SVG/vehicle/PanoramicRoof.tsx +23 -23
  515. package/iconsvg/SVG/vehicle/ParkingAssistants.tsx +24 -24
  516. package/iconsvg/SVG/vehicle/PickYourself.tsx +18 -18
  517. package/iconsvg/SVG/vehicle/PlusIcon.tsx +11 -11
  518. package/iconsvg/SVG/vehicle/Power.tsx +21 -21
  519. package/iconsvg/SVG/vehicle/Ps.tsx +19 -19
  520. package/iconsvg/SVG/vehicle/Question.tsx +24 -24
  521. package/iconsvg/SVG/vehicle/Seats.tsx +21 -21
  522. package/iconsvg/SVG/vehicle/SeatsHeating.tsx +26 -26
  523. package/iconsvg/SVG/vehicle/SelectorGearboxAutomatic.tsx +24 -24
  524. package/iconsvg/SVG/vehicle/SelectorGearboxManualShift.tsx +19 -19
  525. package/iconsvg/SVG/vehicle/SelectorGearboxOther.tsx +24 -24
  526. package/iconsvg/SVG/vehicle/SelectorGearboxSemiAutomatic.tsx +30 -30
  527. package/iconsvg/SVG/vehicle/SelectorInteriorTypeAlcantara.tsx +225 -225
  528. package/iconsvg/SVG/vehicle/SelectorInteriorTypeFabric.tsx +29 -29
  529. package/iconsvg/SVG/vehicle/SelectorInteriorTypeFullLeather.tsx +29 -29
  530. package/iconsvg/SVG/vehicle/SelectorInteriorTypeOther.tsx +26 -26
  531. package/iconsvg/SVG/vehicle/SelectorInteriorTypePartLeather.tsx +142 -142
  532. package/iconsvg/SVG/vehicle/SelectorInteriorTypeSyntheticLeather.tsx +27 -27
  533. package/iconsvg/SVG/vehicle/SelectorInteriorTypeVelours.tsx +39 -39
  534. package/iconsvg/SVG/vehicle/Shield.tsx +39 -39
  535. package/iconsvg/SVG/vehicle/Speedometer.tsx +17 -17
  536. package/iconsvg/SVG/vehicle/StartStopSystem.tsx +30 -30
  537. package/iconsvg/SVG/vehicle/Stop.tsx +25 -25
  538. package/iconsvg/SVG/vehicle/TickMark.tsx +21 -21
  539. package/iconsvg/SVG/vehicle/TrafficSignRecognition.tsx +29 -29
  540. package/iconsvg/SVG/vehicle/TrailerCoupling.tsx +24 -24
  541. package/iconsvg/SVG/vehicle/Transmission.tsx +27 -27
  542. package/iconsvg/SVG/vehicle/Wheel.tsx +43 -43
  543. package/iconsvg/SVG/vehicle/Wipers.tsx +22 -22
  544. package/iconsvg/SVG/vehicle/Wrench.tsx +17 -17
  545. package/iconsvg/index.ts +7 -7
  546. package/index.ts +18 -18
  547. package/locales/de/autobahn.json +676 -671
  548. package/locales/en/autobahn.json +676 -671
  549. package/locales/legacy/SearchDetailedPage.ts +205 -205
  550. package/locales/legacy/cbd.ts +719 -719
  551. package/locales/legacy/common.ts +109 -109
  552. package/locales/legacy/data.ts +1118 -1118
  553. package/locales/legacy/priceRating.ts +10 -10
  554. package/locales/legacy/sortingOptions.ts +21 -21
  555. package/media/images/raiting-stars-min.svg +7 -7
  556. package/media/images/refresh-button.svg +49 -49
  557. package/media/images/user-icon.svg +16 -16
  558. package/media/svg/infoBlocks/whyAutodeIconSet-F.svg +9 -9
  559. package/media/svg/infoBlocks/whyAutodeIconSet-G.svg +8 -8
  560. package/media/svg/infoBlocks/whyAutodeIconSet-Q.svg +6 -6
  561. package/media/svg/infoBlocks/whyAutodeIconSet-R.svg +9 -9
  562. package/media/svg/usp/icon1.svg +16 -16
  563. package/media/svg/usp/icon2.svg +13 -13
  564. package/media/svg/usp/icon3.svg +10 -10
  565. package/media/svg/usp/icon4.svg +14 -14
  566. package/package.json +30 -30
  567. package/schemes/AggregationScheme.ts +73 -73
  568. package/searchFilters/filterOptions.ts +119 -119
  569. package/searchFilters/filterProps.ts +35 -35
  570. package/searchFilters/index.ts +15 -15
  571. package/theme/autobahn.css +25 -25
  572. package/theme/colors_and_type.css +113 -113
  573. package/theme/md3.css +2045 -2034
  574. package/types/types.ts +373 -373
  575. package/types.ts +8 -8
  576. package/ui/Accordion.tsx +134 -134
  577. package/ui/Button.tsx +62 -62
  578. package/ui/CardCarousel.tsx +133 -133
  579. package/ui/Chip.tsx +29 -29
  580. package/ui/DatePicker.tsx +145 -145
  581. package/ui/Dropdown.tsx +205 -205
  582. package/ui/FileUpload.tsx +154 -154
  583. package/ui/FormCheckbox.tsx +79 -79
  584. package/ui/FormDropdown.tsx +327 -327
  585. package/ui/FormField.tsx +88 -88
  586. package/ui/FormRadio.tsx +93 -93
  587. package/ui/FormRadioGroup.tsx +106 -106
  588. package/ui/Icon.tsx +391 -391
  589. package/ui/IconButton.tsx +44 -44
  590. package/ui/Modal.tsx +187 -187
  591. package/ui/Pagination.tsx +140 -140
  592. package/ui/Price.tsx +25 -25
  593. package/ui/PriceEvalBar.tsx +48 -48
  594. package/ui/SaveChip.tsx +34 -34
  595. package/ui/Segmented.tsx +48 -48
  596. package/ui/Skeleton.tsx +75 -75
  597. package/ui/Spec.tsx +24 -24
  598. package/ui/Stars.tsx +29 -29
  599. package/ui/StatChip.tsx +21 -21
  600. package/ui/Stepper.tsx +106 -106
  601. package/ui/Switch.tsx +65 -65
  602. package/ui/Table.tsx +156 -156
  603. package/ui/Textarea.tsx +58 -58
  604. package/ui/index.ts +88 -88
  605. package/utils/CommonUtils.ts +648 -648
  606. package/utils/DateUtils.ts +101 -101
  607. package/utils/index.ts +74 -74
  608. package/utils/power.ts +11 -11
  609. package/utils/query.ts +21 -21
  610. package/vdp/FinanceCalculator.tsx +465 -465
  611. package/vdp/VdpModules.tsx +1490 -1490
  612. package/vdp/VdpViewer.tsx +209 -209
  613. package/vdp/index.ts +75 -75
  614. package/vdp/types.ts +197 -197
  615. package/vehiclesProps/cbdSelectors.ts +117 -117
  616. package/vehiclesProps/decoratedLightProps.tsx +572 -572
  617. package/vehiclesProps/decoratedProps.tsx +1746 -1746
  618. package/vehiclesProps/equipment.ts +129 -129
  619. package/vehiclesProps/vehicleDetails.ts +428 -428
  620. package/widgets/SearchBox.tsx +256 -256
  621. package/widgets/index.ts +5 -5
@@ -1,442 +1,455 @@
1
- // Autobahn (auto.de redesign) — store-car → AutobahnCar mapper (AB-P0-6).
2
- //
3
- // PURE adapter: converts the existing fe-main "store car" (the object
4
- // `SearchResultsStore.getCarsForPage()` returns to the SRP, produced by
5
- // `transformDataForVehicles` in framework/DataTransformers.ts) into the
6
- // `AutobahnCar` view-model the new Autobahn cards consume
7
- // (components/autobahn/cards/types.ts).
8
- //
9
- // WHY a pure function with injected deps:
10
- // The Autobahn cards are pure/presentational and never touch the store. This
11
- // mapper is the single seam that reads the real payload. It is kept pure (no
12
- // store singletons imported here) so it is unit-testable and the SRP container
13
- // injects the real stores/services (imagesStore.getSupportedImageFormat,
14
- // appStore.language). Everything it needs arrives through `deps`.
15
- //
16
- // NEEDS-DATA discipline (the point of the ticket):
17
- // Fields with NO real source on the search payload are left `undefined` so the
18
- // cards render their 'Daten folgt' marker instead of a fabricated number. See
19
- // the per-field rationale in ./fieldMapping.ts. We NEVER synthesize:
20
- // drop, marketLow, marketAvg, marketHigh, watchers, views.
21
- // listPrice / savings are emitted ONLY if a real strike/list price exists.
22
- //
23
- // Every field path below was confirmed against the real code (file:line in
24
- // ./fieldMapping.ts), not guessed.
25
-
26
- import { getPriceRating, getPredictablePrice } from '../utils/CommonUtils';
27
- import { formatTimestamp } from '../utils/DateUtils';
28
- import { getPowerLabel } from '../utils/power';
29
-
30
- import { AutobahnCar, AutobahnPhev } from '../cards/types';
31
- import { TIER_LABELS, RatingTier, CO2_CLASSES, Co2Class } from '../constants';
32
-
33
- /**
34
- * Last-resort placeholder shown in the carousel until the real images for a car
35
- * are loaded. The SRP container SHOULD inject the app's real no-image asset via
36
- * `deps.placeholder` (fe-main exposes PLACEHOLDER_IMAGE_LARGE_URL /
37
- * PLACEHOLDER_IMAGE_SMALL_URL in framework/constants/app.ts, both derived from
38
- * config.imagesAPI.imgUrlBase). We do NOT import that here to keep the mapper
39
- * free of app-config coupling; this empty-data-URI default just guarantees a
40
- * non-broken <img> in tests / before the container wires the real one.
41
- */
42
- export const PLACEHOLDER_IMAGE =
43
- 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
44
-
45
- /**
46
- * Dependencies the SRP container injects. Everything here is what the mapper
47
- * needs from the outside world — keeping the function itself pure.
48
- */
49
- export interface ToAutobahnCarDeps {
50
- /**
51
- * Build a ready-to-use image URL for a car image.
52
- * Pass `imagesStore.getSupportedImageFormat` straight through (it already
53
- * picks webp/jpeg and the cached size). Signature matches ImagesStore:
54
- * (vehicleID, imageIdentifier, size) => url
55
- */
56
- getImageUrl?: (vehicleID: string, imageIdentifier: string, size: 'small' | 'medium' | 'large') => string;
57
- /**
58
- * Loaded gallery images for this car from `imagesStore.images.get(id)`
59
- * (array of { imageUrlSmall, imageUrlMedium, imageUrlLarge, imageUrl, ... }).
60
- * When present we use these real URLs; otherwise we fall back to the single
61
- * main image via getImageUrl, then to the placeholder. Never faked.
62
- */
63
- loadedImages?: Array<{ imageUrlSmall?: string; imageUrlMedium?: string; imageUrlLarge?: string; imageUrl?: string }>;
64
- /** image size used when building gallery URLs from the main image id. */
65
- imageSize?: 'small' | 'medium' | 'large';
66
- /** translator for cbd:* selector codes (fuel/gearbox). Falls back to a built-in de map, then the raw code. */
67
- t?: (key: string, options?: object) => string;
68
- /** active UI language ('de' | 'en' …). Drives de-DE vs en-IN number grouping for the EnVKV line. */
69
- language?: string;
70
- /** placeholder image URL override (defaults to PLACEHOLDER_IMAGE). */
71
- placeholder?: string;
72
- }
73
-
74
- // ---------------------------------------------------------------------------
75
- // small pure helpers
76
- // ---------------------------------------------------------------------------
77
-
78
- const DEFAULT_LANG = 'de';
79
-
80
- /** locale tag for Number#toLocaleString — de-DE (comma decimals) unless en. */
81
- function localeTag(language?: string): string {
82
- return language === 'en' ? 'en-IN' : 'de-DE';
83
- }
84
-
85
- /** finite-number coercion: accepts number | numeric string, else undefined. */
86
- function num(v: any): number | undefined {
87
- if (v == null) return undefined;
88
- const n = typeof v === 'number' ? v : Number.parseFloat(String(v));
89
- return Number.isFinite(n) ? n : undefined;
90
- }
91
-
92
- /**
93
- * Minimal de-DE fallback for the handful of cbd:* selector codes the cards show
94
- * (fuel + gearbox). Used only when no `t` is injected (e.g. in unit tests).
95
- * The full set lives in the cbd locale dictionary (@bytebrand/i18n-dictionaries).
96
- */
97
- const CBD_DE_FALLBACK: Record<string, string> = {
98
- selector_fuel_petrol: 'Benzin',
99
- selector_fuel_diesel: 'Diesel',
100
- selector_fuel_electrical: 'Elektro',
101
- selector_fuel_ethanol: 'Ethanol',
102
- selector_fuel_hybridElectricalDiesel: 'Hybrid (Elektro / Diesel)',
103
- selector_fuel_hybridElectricalPetrol: 'Hybrid (Elektro / Benzin)',
104
- selector_fuel_hydrogen: 'Wasserstoff',
105
- selector_fuel_naturalGas: 'Erdgas',
106
- selector_gearbox_automatic: 'Automatik',
107
- selector_gearbox_manualShift: 'Manuell',
108
- selector_gearbox_semiAutomatic: 'Halbautomatik',
109
- // highlight-chip keys (DataTransformers highlights) — used when no `t` is injected
110
- multimedia_navigationSystem: 'Navigationssystem',
111
- lights_ledHeadlights: 'LED-Scheinwerfer',
112
- lights_xenonHeadlights: 'Xenon-Scheinwerfer',
113
- window_panoramicGlassRoof: 'Panoramadach',
114
- assistants_headUpDisplay: 'Head-up-Display',
115
- assistants_adaptiveCruiseControl: 'Abstandstempomat',
116
- search_seatHeating: 'Sitzheizung',
117
- selector_climatisation_automaticAirCondition: 'Klimaautomatik',
118
- selector_climatisation_airCondition: 'Klimaanlage',
119
- search_parkingAssistants: 'Einparkhilfe',
120
- selector_driveType_allWheelDrive: 'Allradantrieb',
121
- search_trailerHitch: 'Anhängerkupplung',
122
- assistants_cruiseControl: 'Tempomat',
123
- assistants_trafficSignRecognition: 'Verkehrszeichenerkennung',
124
- assistants_collisionAvoidance: 'Notbremsassistent',
125
- window_sunroof: 'Schiebedach',
126
- seats_electricAdjustable: 'Elektr. Sitze',
127
- exterior_metallic: 'Metallic-Lackierung',
128
- multimedia_handsFreePhoneSystem: 'Freisprecheinrichtung',
129
- heatingCooling_auxiliaryHeating: 'Standheizung',
130
- multimedia_bluetooth: 'Bluetooth',
131
- };
132
-
133
- /** translate a cbd:* selector code → human label. */
134
- function cbd(code: any, t?: (key: string, options?: object) => string): string {
135
- if (code == null || code === 'N/A') return '';
136
- const key = String(code);
137
- if (t) {
138
- const out = t(`cbd:${key}`);
139
- // i18next returns the key back when missing; treat that as "no translation".
140
- if (out && out !== `cbd:${key}` && out !== key) return out;
141
- }
142
- return CBD_DE_FALLBACK[key] || key;
143
- }
144
-
145
- /**
146
- * Map the store's energy-efficiency-class selector code (or a bare letter) to a
147
- * single CO2_CLASSES letter ('A'…'G'). A+/A++/A+++ collapse to 'A' so the card's
148
- * colored InlineCls (which does CO2_CLASSES.indexOf) still resolves a band color.
149
- * Returns '' when there is no class (caller decides what to render).
150
- */
151
- function co2ClassLetter(code: any): Co2Class | '' {
152
- if (code == null || code === 'N/A') return '';
153
- const raw = String(code);
154
- // selector_energyEfficiencyClass_appp → 'a', _ap → 'a', _b → 'b', …
155
- const m = raw.match(/selector_energyEfficiencyClass_(a|b|c|d|e|f|g)/i);
156
- const letter = (m ? m[1] : raw.replace(/\+/g, '').trim().charAt(0)).toUpperCase();
157
- return (CO2_CLASSES as readonly string[]).includes(letter) ? (letter as Co2Class) : '';
158
- }
159
-
160
- /**
161
- * Real Preisbewertung → AutobahnCar rating tone + German label.
162
- *
163
- * Source of truth (confirmed against the live SRP card,
164
- * VehicleSmallCard/VehicleInfo.tsx:160): the legacy card renders
165
- * getPriceRating(price.currentSalesPrice, price.mlCurrentSalesPricePredicted)
166
- * which returns a numeric tier using priceRatings:
167
- * 0 noRating · 1 highPrice · 2 increasedPrice · 3 fairPrice · 4 goodPrice · 5 topPrice
168
- * (constants/price.ts in this package).
169
- *
170
- * We map that real number onto the Autobahn 5-tier scale (TIER_LABELS,
171
- * components/autobahn/constants.ts), where index 0=Top … 4=Hoch:
172
- * topPrice(5)→0 'Top Preis' · goodPrice(4)→1 'Guter Preis' ·
173
- * fairPrice(3)→2 'Fairer Preis' · increasedPrice(2)→3 'Erhöht' ·
174
- * highPrice(1)→4 'Hoher Preis'.
175
- * noRating(0) has no real comparison → neutral 'Fairer Preis' (tier 2) WITHOUT a
176
- * flattering label (documented in fieldMapping.ts). The card only special-cases
177
- * the 'fair' tone (warn pill); every other tone is the good/green pill.
178
- *
179
- * AutobahnCar.rating is a free string; CarCard does `rating === 'fair' ? warn : good`.
180
- * We emit the autobahn tier key ('top'|'good'|'fair'|'raised'|'high') so the
181
- * neutral 'fair' maps to the warn pill exactly like the design intends.
182
- */
183
- const LEGACY_TO_TIER: Record<number, RatingTier> = {
184
- 5: 0, // topPrice → Top Preis
185
- 4: 1, // goodPrice → Guter Preis
186
- 3: 2, // fairPrice → Fairer Preis
187
- 2: 3, // increasedPrice → Erhöht
188
- 1: 4, // highPrice → Hoher Preis
189
- };
190
- const TIER_TONE: Record<RatingTier, string> = {
191
- 0: 'top',
192
- 1: 'good',
193
- 2: 'fair',
194
- 3: 'raised',
195
- 4: 'high',
196
- };
197
-
198
- function mapRating(currentSalesPrice?: number, predicted?: number): { rating: string; ratingLabel: string } {
199
- const legacy = getPriceRating(currentSalesPrice as number, predicted as number); // 0..5
200
- // 0 = noRating: keep neutral (tier 2) — never invent a flattering rating.
201
- const tier: RatingTier = legacy === 0 ? 2 : LEGACY_TO_TIER[legacy] ?? 2;
202
- return { rating: TIER_TONE[tier], ratingLabel: TIER_LABELS[tier] };
203
- }
204
-
205
- /** Is this car a plug-in hybrid? Determined by fuel type, mirroring ADV-88 in VehicleInfo.tsx. */
206
- function isPluginHybrid(fuel: any): boolean {
207
- return fuel === 'selector_fuel_hybridElectricalDiesel' || fuel === 'selector_fuel_hybridElectricalPetrol';
208
- }
209
-
210
- /** Build the gallery URL list from real images, falling back to main image, then placeholder. */
211
- function buildGallery(storeCar: any, deps: ToAutobahnCarDeps): string[] {
212
- const placeholder = deps.placeholder || PLACEHOLDER_IMAGE;
213
- // Only 'small' and 'large' variants are pre-generated by image-generator; 'medium' has no cached file.
214
- const size = deps.imageSize || 'small';
215
-
216
- // 1) Real loaded images from imagesStore.images.get(id).
217
- if (Array.isArray(deps.loadedImages) && deps.loadedImages.length) {
218
- const urls = deps.loadedImages
219
- .map((img) =>
220
- size === 'large'
221
- ? img.imageUrlLarge || img.imageUrlMedium || img.imageUrl
222
- : size === 'small'
223
- ? img.imageUrlSmall || img.imageUrlMedium || img.imageUrl
224
- : img.imageUrlMedium || img.imageUrlLarge || img.imageUrl
225
- )
226
- .filter((u): u is string => !!u);
227
- if (urls.length) return urls;
228
- }
229
-
230
- // 2) Not loaded yet, but we have a main image id + a URL builder → single real image.
231
- const id = storeCar.id;
232
- const mainImageId = storeCar.mainImageId;
233
- const hasImages = num(storeCar.imagesCount);
234
- if (deps.getImageUrl && id && mainImageId && hasImages) {
235
- const url = deps.getImageUrl(id, mainImageId, size);
236
- if (url) return [url];
237
- }
238
-
239
- // 3) Nothing real yet — single placeholder (never a fabricated photo).
240
- return [placeholder];
241
- }
242
-
243
- /** Build the optional PHEV EnVKV sub-block when the car is a plug-in hybrid and weighted data exists. */
244
- function buildPhev(storeCar: any, language?: string): AutobahnPhev | undefined {
245
- const c = storeCar.consumption || {};
246
- const e = storeCar.environmentEmissions || {};
247
- if (!isPluginHybrid(c.fuel)) return undefined;
248
-
249
- const consEl = num(c.wltpWeightedPowerCombined) ?? num(c.consumptionPowerCombined);
250
- const consFuel = num(c.wltpWeightedCombined);
251
- const consDis = num(c.wltpCombined) ?? num(c.consumptionCombined);
252
- const co2w = num(e.wltpCo2) ?? num(e.co2);
253
- const clsW = co2ClassLetter(e.wltpEnergyEfficiencyClass);
254
- const clsD = co2ClassLetter(e.wltpDischargedEnergyEfficiencyClass);
255
-
256
- // Only emit the dual PHEV line when we actually have the weighted figures the
257
- // EcoLine PHEV branch needs; otherwise let the normal single line render.
258
- if (consEl == null || consFuel == null || co2w == null) return undefined;
259
-
260
- return {
261
- consEl: `${consEl.toLocaleString(localeTag(language))} kWh/100 km`,
262
- consFuel: `${consFuel.toLocaleString(localeTag(language))} l/100 km`,
263
- consDis: consDis != null ? `${consDis.toLocaleString(localeTag(language))} l/100 km` : '–',
264
- co2w: `${co2w.toLocaleString(localeTag(language))} g/km`,
265
- co2classW: clsW || '–',
266
- co2classD: clsD || clsW || '–',
267
- };
268
- }
269
-
270
- // ---------------------------------------------------------------------------
271
- // main mapper
272
- // ---------------------------------------------------------------------------
273
-
274
- /**
275
- * Convert one fe-main store car → AutobahnCar.
276
- *
277
- * @param storeCar the object from SearchResultsStore.getCarsForPage()
278
- * (shape = transformDataForVehicles output). `any` because the store car is
279
- * itself untyped (`getCarsForPage: (page) => any[]`).
280
- * @param deps injected services/locale (see ToAutobahnCarDeps). Optional so the
281
- * mapper still runs in tests with zero wiring (gallery → placeholder, labels →
282
- * built-in de fallback).
283
- */
284
- export function toAutobahnCar(storeCar: any, deps: ToAutobahnCarDeps = {}): AutobahnCar {
285
- const language = deps.language || DEFAULT_LANG;
286
- const t = deps.t;
287
-
288
- const title = storeCar.title || {};
289
- const info = storeCar.info || {};
290
- const engineData = storeCar.engineData || {};
291
- const consumption = storeCar.consumption || {};
292
- const emissions = storeCar.environmentEmissions || {};
293
- const price = storeCar.price || {};
294
-
295
- // --- price / monthly (REQUIRED) ---
296
- // monthly ← price.financing.monthlyInstallment. This is the financing rate
297
- // produced by FinancingStore via getComputedFinancing(config).financing
298
- // (getFinancing.ts:82 `monthlyInstallment`), spread into price.financing by
299
- // transformDataForVehicles (DataTransformers.ts:345). It is the LEAD price.
300
- const monthly = num(price?.financing?.monthlyInstallment) ?? 0;
301
- // price ← price.currentSalesPrice (DataTransformers.ts:352).
302
- const purchase = num(price?.currentSalesPrice) ?? 0;
303
-
304
- // --- rating (REQUIRED-WHEN-PRICED) ← real Preisbewertung ---
305
- // BL-08 (P1, MONEY): getPriceRating(0, 0) mathematically resolves to tier 5
306
- // ("Top Preis" — the BEST possible rating). Its internal min/max bands are all
307
- // `predicted * (1 ± pct)`, which collapse to 0 when predicted is 0, and the
308
- // topPrice branch checks `currentSalesPrice <= min` — 0 <= 0 is true. A
309
- // missing/broken price payload must NEVER get dressed up as the best deal on
310
- // the lot. Only compute/emit a rating when there is a real, positive sales
311
- // price; otherwise rating/ratingLabel stay '' (falsy) — every consumer
312
- // (CarCard.tsx, cardParts.tsx, FinanceCalculator.tsx) already treats a falsy
313
- // rating as "no badge", so no type change is needed here.
314
- const predicted =
315
- purchase > 0 ? getPredictablePrice(purchase, num(price?.mlCurrentSalesPricePredicted) as number) : undefined;
316
- const { rating, ratingLabel } = purchase > 0 ? mapRating(purchase, predicted) : { rating: '', ratingLabel: '' };
317
-
318
- // --- key specs ---
319
- const powerKW = num(engineData.powerKW);
320
- const powerPS = num(engineData.powerPS);
321
- const power = getPowerLabel(powerKW as number, powerPS as number); // "150 kW (204 PS)"
322
-
323
- const regTs = num(info.regDate);
324
- const reg = regTs ? formatTimestamp({ timestamp: regTs, format: 'MM/YYYY' }) : '';
325
-
326
- const ownersN = num(info.numberOfPreviousOwners);
327
-
328
- // --- EnVKV consumption line (REQUIRED on every German car ad) ---
329
- // Prefer WLTP figures when present (the legacy cards do too), else NEDC.
330
- const consVal = num(consumption.wltpCombined) ?? num(consumption.consumptionCombined);
331
- const co2Val = num(emissions.wltpCo2) ?? num(emissions.co2);
332
- const cons = consVal != null ? `${consVal.toLocaleString(localeTag(language))} l/100 km` : '';
333
- const co2 = co2Val != null ? `${co2Val.toLocaleString(localeTag(language))} g/km` : '';
334
- const co2class = co2ClassLetter(emissions.wltpEnergyEfficiencyClass);
335
- const phev = buildPhev(storeCar, language);
336
-
337
- // --- media ---
338
- const gallery = buildGallery(storeCar, deps);
339
- const photos = num(storeCar.imagesCount) ?? 0;
340
-
341
- // --- optional: leasing rate — ONLY when leasing is actually active for this car.
342
- // SearchResultsStore.getCarsForPage stamps price.leasing.isActive via getLeasingActive
343
- // (car age + mileage within the leasing limits). Legacy SRP shows "Leasing ---" when
344
- // inactive; we mirror that by leaving `lease` undefined so PricePaths omits the row
345
- // (instead of computing/showing a leasing rate the car isn't eligible for).
346
- const leasingActive = !!(price && price.leasing && price.leasing.isActive);
347
- const lease = leasingActive ? num(price?.leasing?.monthlyInstallment) : undefined;
348
-
349
- // --- optional: list price / savings — ONLY from a real strike price ---
350
- // transformDataForVehicles exposes oldMonthlyInstallment / highestPrice via
351
- // the financing spread, and price.historyPriceDifference. There is NO reliable
352
- // purchase-price strike on the search payload today, so we leave listPrice /
353
- // savings UNDEFINED unless a real highestPrice strike exists above the sale
354
- // price. See fieldMapping.ts — flagged for backend confirmation.
355
- const isStrikeShown = !!price?.financing?.isStrikeShown;
356
- const highest = num(price?.financing?.highestPrice) ?? num(price?.highestPrice);
357
- let listPrice: number | undefined;
358
- let savings: number | undefined;
359
- if (isStrikeShown && highest != null && purchase > 0 && highest > purchase) {
360
- listPrice = highest;
361
- savings = highest - purchase;
362
- }
363
-
364
- // --- price drop (REAL) — mirrors the legacy SRL green "−X €" badge: show the reduction only
365
- // when price.historyPriceDifference is a meaningful amount (≥ 500 €, the legacy threshold).
366
- const histDrop = num(price?.historyPriceDifference);
367
- const drop = histDrop != null && histDrop >= 500 ? histDrop : undefined;
368
- // percent reduction (historyPriceDifferencePerCent) — paired with `drop` for the −X% badge.
369
- const histPct = num(price?.historyPriceDifferencePerCent);
370
- const dropPct = drop != null && histPct != null && histPct > 0 ? Math.round(histPct) : undefined;
371
-
372
- // --- NEU badge (REAL) — the legacy showNewLabel flag carried on the store car. ---
373
- const isNew = !!storeCar.showNewLabel;
374
-
375
- // --- availability (REAL) — offer.availabilityMode. 'always' → immediately available. ---
376
- const offer = storeCar.offer && typeof storeCar.offer === 'object' ? storeCar.offer : {};
377
- const availability =
378
- offer.availabilityMode === 'selector_availabilityMode_always'
379
- ? t
380
- ? t('autobahn:availability.immediately')
381
- : 'Sofort verfügbar'
382
- : undefined;
383
- // 0 € Anzahlung available — transform sets offer.showDownPayment = (raw showDownPayment && zero first installment).
384
- const zeroDown = !!offer.showDownPayment;
385
-
386
- const carView: AutobahnCar = {
387
- // identity / headline
388
- make: String(title.make ?? ''),
389
- model: String(title.model ?? ''),
390
- trim: String(title.subModel ?? ''),
391
-
392
- // key specs
393
- km: num(info.mileage) ?? 0,
394
- reg,
395
- power,
396
- fuel: cbd(consumption.fuel, t),
397
- gear: cbd(info.gearbox, t),
398
- owners: ownersN ?? 0,
399
-
400
- // price
401
- monthly,
402
- price: purchase,
403
-
404
- // media
405
- gallery,
406
- photos,
407
-
408
- // EnVKV
409
- cons,
410
- co2,
411
- co2class: co2class || '',
412
- ...(phev ? { phev } : {}),
413
-
414
- // trust / features — equipment highlight chips (Matrix-LED, Virtual Cockpit, AHK, ACC, …).
415
- // transformDataForVehicles extracted the present highlight selector-keys via getActualHighlights
416
- // (reading the raw equipment categories); translate them to labels here (cbd → t('cbd:<key>')).
417
- // First 4, like the design's card. Empty when the car has no notable equipment.
418
- features: (Array.isArray((storeCar as any).highlights) ? (storeCar as any).highlights : [])
419
- .map((k: any) => cbd(k, t))
420
- .filter((s: string) => !!s)
421
- .slice(0, 4),
422
- rating,
423
- ratingLabel,
424
-
425
- // optional (only when real)
426
- ...(listPrice != null ? { listPrice } : {}),
427
- ...(savings != null ? { savings } : {}),
428
- ...(lease != null ? { lease } : {}),
429
- ...(drop != null ? { drop } : {}),
430
- ...(dropPct != null ? { dropPct } : {}),
431
- ...(zeroDown ? { zeroDown } : {}),
432
- ...(isNew ? { isNew } : {}),
433
- ...(availability ? { availability } : {}),
434
-
435
- // NEEDS-DATA: deliberately omitted (marketLow, marketAvg, marketHigh, watchers, views).
436
- // The cards render 'Daten folgt' for these until a real backend exists.
437
- };
438
-
439
- return carView;
440
- }
441
-
442
- export default toAutobahnCar;
1
+ // Autobahn (auto.de redesign) — store-car → AutobahnCar mapper (AB-P0-6).
2
+ //
3
+ // PURE adapter: converts the existing fe-main "store car" (the object
4
+ // `SearchResultsStore.getCarsForPage()` returns to the SRP, produced by
5
+ // `transformDataForVehicles` in framework/DataTransformers.ts) into the
6
+ // `AutobahnCar` view-model the new Autobahn cards consume
7
+ // (components/autobahn/cards/types.ts).
8
+ //
9
+ // WHY a pure function with injected deps:
10
+ // The Autobahn cards are pure/presentational and never touch the store. This
11
+ // mapper is the single seam that reads the real payload. It is kept pure (no
12
+ // store singletons imported here) so it is unit-testable and the SRP container
13
+ // injects the real stores/services (imagesStore.getSupportedImageFormat,
14
+ // appStore.language). Everything it needs arrives through `deps`.
15
+ //
16
+ // NEEDS-DATA discipline (the point of the ticket):
17
+ // Fields with NO real source on the search payload are left `undefined` so the
18
+ // cards render their 'Daten folgt' marker instead of a fabricated number. See
19
+ // the per-field rationale in ./fieldMapping.ts. We NEVER synthesize:
20
+ // drop, marketLow, marketAvg, marketHigh, watchers, views.
21
+ // listPrice / savings are emitted ONLY if a real strike/list price exists.
22
+ //
23
+ // Every field path below was confirmed against the real code (file:line in
24
+ // ./fieldMapping.ts), not guessed.
25
+
26
+ import { getPriceRating, getPredictablePrice } from '../utils/CommonUtils';
27
+ import { formatTimestamp } from '../utils/DateUtils';
28
+ import { getPowerLabel } from '../utils/power';
29
+
30
+ import { AutobahnCar, AutobahnPhev } from '../cards/types';
31
+ import { TIER_LABELS, RatingTier, CO2_CLASSES, Co2Class } from '../constants';
32
+
33
+ /**
34
+ * Last-resort placeholder shown in the carousel until the real images for a car
35
+ * are loaded. The SRP container SHOULD inject the app's real no-image asset via
36
+ * `deps.placeholder` (fe-main exposes PLACEHOLDER_IMAGE_LARGE_URL /
37
+ * PLACEHOLDER_IMAGE_SMALL_URL in framework/constants/app.ts, both derived from
38
+ * config.imagesAPI.imgUrlBase). We do NOT import that here to keep the mapper
39
+ * free of app-config coupling; this empty-data-URI default just guarantees a
40
+ * non-broken <img> in tests / before the container wires the real one.
41
+ */
42
+ export const PLACEHOLDER_IMAGE =
43
+ 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
44
+
45
+ /**
46
+ * Dependencies the SRP container injects. Everything here is what the mapper
47
+ * needs from the outside world — keeping the function itself pure.
48
+ */
49
+ export interface ToAutobahnCarDeps {
50
+ /**
51
+ * Build a ready-to-use image URL for a car image.
52
+ * Pass `imagesStore.getSupportedImageFormat` straight through (it already
53
+ * picks webp/jpeg and the cached size). Signature matches ImagesStore:
54
+ * (vehicleID, imageIdentifier, size) => url
55
+ */
56
+ getImageUrl?: (vehicleID: string, imageIdentifier: string, size: 'small' | 'medium' | 'large') => string;
57
+ /**
58
+ * Loaded gallery images for this car from `imagesStore.images.get(id)`
59
+ * (array of { imageUrlSmall, imageUrlMedium, imageUrlLarge, imageUrl, ... }).
60
+ * When present we use these real URLs; otherwise we fall back to the single
61
+ * main image via getImageUrl, then to the placeholder. Never faked.
62
+ */
63
+ loadedImages?: Array<{ imageUrlSmall?: string; imageUrlMedium?: string; imageUrlLarge?: string; imageUrl?: string }>;
64
+ /** image size used when building gallery URLs from the main image id. */
65
+ imageSize?: 'small' | 'medium' | 'large';
66
+ /** translator for cbd:* selector codes (fuel/gearbox). Falls back to a built-in de map, then the raw code. */
67
+ t?: (key: string, options?: object) => string;
68
+ /** active UI language ('de' | 'en' …). Drives de-DE vs en-IN number grouping for the EnVKV line. */
69
+ language?: string;
70
+ /** placeholder image URL override (defaults to PLACEHOLDER_IMAGE). */
71
+ placeholder?: string;
72
+ /**
73
+ * Buyer-activity stats for this car — UserActionsAPI 'stats/viewers' response, loaded async and
74
+ * keyed by carId (`searchStore.statsData.get(storeCar.id)`). Pass it straight through; absent
75
+ * (not loaded yet, or no stats for this car) → viewsCount/favoritesCount stay undefined and the
76
+ * gallery badge row simply omits those pills. Never fabricated.
77
+ */
78
+ stats?: { totalCarImpCount?: number; totalFavCount?: number };
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // small pure helpers
83
+ // ---------------------------------------------------------------------------
84
+
85
+ const DEFAULT_LANG = 'de';
86
+
87
+ /** locale tag for Number#toLocaleString — de-DE (comma decimals) unless en. */
88
+ function localeTag(language?: string): string {
89
+ return language === 'en' ? 'en-IN' : 'de-DE';
90
+ }
91
+
92
+ /** finite-number coercion: accepts number | numeric string, else undefined. */
93
+ function num(v: any): number | undefined {
94
+ if (v == null) return undefined;
95
+ const n = typeof v === 'number' ? v : Number.parseFloat(String(v));
96
+ return Number.isFinite(n) ? n : undefined;
97
+ }
98
+
99
+ /**
100
+ * Minimal de-DE fallback for the handful of cbd:* selector codes the cards show
101
+ * (fuel + gearbox). Used only when no `t` is injected (e.g. in unit tests).
102
+ * The full set lives in the cbd locale dictionary (@bytebrand/i18n-dictionaries).
103
+ */
104
+ const CBD_DE_FALLBACK: Record<string, string> = {
105
+ selector_fuel_petrol: 'Benzin',
106
+ selector_fuel_diesel: 'Diesel',
107
+ selector_fuel_electrical: 'Elektro',
108
+ selector_fuel_ethanol: 'Ethanol',
109
+ selector_fuel_hybridElectricalDiesel: 'Hybrid (Elektro / Diesel)',
110
+ selector_fuel_hybridElectricalPetrol: 'Hybrid (Elektro / Benzin)',
111
+ selector_fuel_hydrogen: 'Wasserstoff',
112
+ selector_fuel_naturalGas: 'Erdgas',
113
+ selector_gearbox_automatic: 'Automatik',
114
+ selector_gearbox_manualShift: 'Manuell',
115
+ selector_gearbox_semiAutomatic: 'Halbautomatik',
116
+ // highlight-chip keys (DataTransformers highlights) — used when no `t` is injected
117
+ multimedia_navigationSystem: 'Navigationssystem',
118
+ lights_ledHeadlights: 'LED-Scheinwerfer',
119
+ lights_xenonHeadlights: 'Xenon-Scheinwerfer',
120
+ window_panoramicGlassRoof: 'Panoramadach',
121
+ assistants_headUpDisplay: 'Head-up-Display',
122
+ assistants_adaptiveCruiseControl: 'Abstandstempomat',
123
+ search_seatHeating: 'Sitzheizung',
124
+ selector_climatisation_automaticAirCondition: 'Klimaautomatik',
125
+ selector_climatisation_airCondition: 'Klimaanlage',
126
+ search_parkingAssistants: 'Einparkhilfe',
127
+ selector_driveType_allWheelDrive: 'Allradantrieb',
128
+ search_trailerHitch: 'Anhängerkupplung',
129
+ assistants_cruiseControl: 'Tempomat',
130
+ assistants_trafficSignRecognition: 'Verkehrszeichenerkennung',
131
+ assistants_collisionAvoidance: 'Notbremsassistent',
132
+ window_sunroof: 'Schiebedach',
133
+ seats_electricAdjustable: 'Elektr. Sitze',
134
+ exterior_metallic: 'Metallic-Lackierung',
135
+ multimedia_handsFreePhoneSystem: 'Freisprecheinrichtung',
136
+ heatingCooling_auxiliaryHeating: 'Standheizung',
137
+ multimedia_bluetooth: 'Bluetooth',
138
+ };
139
+
140
+ /** translate a cbd:* selector code → human label. */
141
+ function cbd(code: any, t?: (key: string, options?: object) => string): string {
142
+ if (code == null || code === 'N/A') return '';
143
+ const key = String(code);
144
+ if (t) {
145
+ const out = t(`cbd:${key}`);
146
+ // i18next returns the key back when missing; treat that as "no translation".
147
+ if (out && out !== `cbd:${key}` && out !== key) return out;
148
+ }
149
+ return CBD_DE_FALLBACK[key] || key;
150
+ }
151
+
152
+ /**
153
+ * Map the store's energy-efficiency-class selector code (or a bare letter) to a
154
+ * single CO2_CLASSES letter ('A'…'G'). A+/A++/A+++ collapse to 'A' so the card's
155
+ * colored InlineCls (which does CO2_CLASSES.indexOf) still resolves a band color.
156
+ * Returns '' when there is no class (caller decides what to render).
157
+ */
158
+ function co2ClassLetter(code: any): Co2Class | '' {
159
+ if (code == null || code === 'N/A') return '';
160
+ const raw = String(code);
161
+ // selector_energyEfficiencyClass_appp → 'a', _ap → 'a', _b → 'b', …
162
+ const m = raw.match(/selector_energyEfficiencyClass_(a|b|c|d|e|f|g)/i);
163
+ const letter = (m ? m[1] : raw.replace(/\+/g, '').trim().charAt(0)).toUpperCase();
164
+ return (CO2_CLASSES as readonly string[]).includes(letter) ? (letter as Co2Class) : '';
165
+ }
166
+
167
+ /**
168
+ * Real Preisbewertung → AutobahnCar rating tone + German label.
169
+ *
170
+ * Source of truth (confirmed against the live SRP card,
171
+ * VehicleSmallCard/VehicleInfo.tsx:160): the legacy card renders
172
+ * getPriceRating(price.currentSalesPrice, price.mlCurrentSalesPricePredicted)
173
+ * which returns a numeric tier using priceRatings:
174
+ * 0 noRating · 1 highPrice · 2 increasedPrice · 3 fairPrice · 4 goodPrice · 5 topPrice
175
+ * (constants/price.ts in this package).
176
+ *
177
+ * We map that real number onto the Autobahn 5-tier scale (TIER_LABELS,
178
+ * components/autobahn/constants.ts), where index 0=Top … 4=Hoch:
179
+ * topPrice(5)→0 'Top Preis' · goodPrice(4)→1 'Guter Preis' ·
180
+ * fairPrice(3)→2 'Fairer Preis' · increasedPrice(2)→3 'Erhöht' ·
181
+ * highPrice(1)→4 'Hoher Preis'.
182
+ * noRating(0) has no real comparison → neutral 'Fairer Preis' (tier 2) WITHOUT a
183
+ * flattering label (documented in fieldMapping.ts). The card only special-cases
184
+ * the 'fair' tone (warn pill); every other tone is the good/green pill.
185
+ *
186
+ * AutobahnCar.rating is a free string; CarCard does `rating === 'fair' ? warn : good`.
187
+ * We emit the autobahn tier key ('top'|'good'|'fair'|'raised'|'high') so the
188
+ * neutral 'fair' maps to the warn pill exactly like the design intends.
189
+ */
190
+ const LEGACY_TO_TIER: Record<number, RatingTier> = {
191
+ 5: 0, // topPrice → Top Preis
192
+ 4: 1, // goodPrice → Guter Preis
193
+ 3: 2, // fairPrice → Fairer Preis
194
+ 2: 3, // increasedPrice → Erhöht
195
+ 1: 4, // highPrice → Hoher Preis
196
+ };
197
+ const TIER_TONE: Record<RatingTier, string> = {
198
+ 0: 'top',
199
+ 1: 'good',
200
+ 2: 'fair',
201
+ 3: 'raised',
202
+ 4: 'high',
203
+ };
204
+
205
+ function mapRating(currentSalesPrice?: number, predicted?: number): { rating: string; ratingLabel: string } {
206
+ const legacy = getPriceRating(currentSalesPrice as number, predicted as number); // 0..5
207
+ // 0 = noRating: keep neutral (tier 2) — never invent a flattering rating.
208
+ const tier: RatingTier = legacy === 0 ? 2 : LEGACY_TO_TIER[legacy] ?? 2;
209
+ return { rating: TIER_TONE[tier], ratingLabel: TIER_LABELS[tier] };
210
+ }
211
+
212
+ /** Is this car a plug-in hybrid? Determined by fuel type, mirroring ADV-88 in VehicleInfo.tsx. */
213
+ function isPluginHybrid(fuel: any): boolean {
214
+ return fuel === 'selector_fuel_hybridElectricalDiesel' || fuel === 'selector_fuel_hybridElectricalPetrol';
215
+ }
216
+
217
+ /** Build the gallery URL list from real images, falling back to main image, then placeholder. */
218
+ function buildGallery(storeCar: any, deps: ToAutobahnCarDeps): string[] {
219
+ const placeholder = deps.placeholder || PLACEHOLDER_IMAGE;
220
+ // Only 'small' and 'large' variants are pre-generated by image-generator; 'medium' has no cached file.
221
+ const size = deps.imageSize || 'small';
222
+
223
+ // 1) Real loaded images from imagesStore.images.get(id).
224
+ if (Array.isArray(deps.loadedImages) && deps.loadedImages.length) {
225
+ const urls = deps.loadedImages
226
+ .map((img) =>
227
+ size === 'large'
228
+ ? img.imageUrlLarge || img.imageUrlMedium || img.imageUrl
229
+ : size === 'small'
230
+ ? img.imageUrlSmall || img.imageUrlMedium || img.imageUrl
231
+ : img.imageUrlMedium || img.imageUrlLarge || img.imageUrl
232
+ )
233
+ .filter((u): u is string => !!u);
234
+ if (urls.length) return urls;
235
+ }
236
+
237
+ // 2) Not loaded yet, but we have a main image id + a URL builder → single real image.
238
+ const id = storeCar.id;
239
+ const mainImageId = storeCar.mainImageId;
240
+ const hasImages = num(storeCar.imagesCount);
241
+ if (deps.getImageUrl && id && mainImageId && hasImages) {
242
+ const url = deps.getImageUrl(id, mainImageId, size);
243
+ if (url) return [url];
244
+ }
245
+
246
+ // 3) Nothing real yet — single placeholder (never a fabricated photo).
247
+ return [placeholder];
248
+ }
249
+
250
+ /** Build the optional PHEV EnVKV sub-block when the car is a plug-in hybrid and weighted data exists. */
251
+ function buildPhev(storeCar: any, language?: string): AutobahnPhev | undefined {
252
+ const c = storeCar.consumption || {};
253
+ const e = storeCar.environmentEmissions || {};
254
+ if (!isPluginHybrid(c.fuel)) return undefined;
255
+
256
+ const consEl = num(c.wltpWeightedPowerCombined) ?? num(c.consumptionPowerCombined);
257
+ const consFuel = num(c.wltpWeightedCombined);
258
+ const consDis = num(c.wltpCombined) ?? num(c.consumptionCombined);
259
+ const co2w = num(e.wltpCo2) ?? num(e.co2);
260
+ const clsW = co2ClassLetter(e.wltpEnergyEfficiencyClass);
261
+ const clsD = co2ClassLetter(e.wltpDischargedEnergyEfficiencyClass);
262
+
263
+ // Only emit the dual PHEV line when we actually have the weighted figures the
264
+ // EcoLine PHEV branch needs; otherwise let the normal single line render.
265
+ if (consEl == null || consFuel == null || co2w == null) return undefined;
266
+
267
+ return {
268
+ consEl: `${consEl.toLocaleString(localeTag(language))} kWh/100 km`,
269
+ consFuel: `${consFuel.toLocaleString(localeTag(language))} l/100 km`,
270
+ consDis: consDis != null ? `${consDis.toLocaleString(localeTag(language))} l/100 km` : '–',
271
+ co2w: `${co2w.toLocaleString(localeTag(language))} g/km`,
272
+ co2classW: clsW || '–',
273
+ co2classD: clsD || clsW || '–',
274
+ };
275
+ }
276
+
277
+ // ---------------------------------------------------------------------------
278
+ // main mapper
279
+ // ---------------------------------------------------------------------------
280
+
281
+ /**
282
+ * Convert one fe-main store car → AutobahnCar.
283
+ *
284
+ * @param storeCar the object from SearchResultsStore.getCarsForPage()
285
+ * (shape = transformDataForVehicles output). `any` because the store car is
286
+ * itself untyped (`getCarsForPage: (page) => any[]`).
287
+ * @param deps injected services/locale (see ToAutobahnCarDeps). Optional so the
288
+ * mapper still runs in tests with zero wiring (gallery → placeholder, labels →
289
+ * built-in de fallback).
290
+ */
291
+ export function toAutobahnCar(storeCar: any, deps: ToAutobahnCarDeps = {}): AutobahnCar {
292
+ const language = deps.language || DEFAULT_LANG;
293
+ const t = deps.t;
294
+
295
+ const title = storeCar.title || {};
296
+ const info = storeCar.info || {};
297
+ const engineData = storeCar.engineData || {};
298
+ const consumption = storeCar.consumption || {};
299
+ const emissions = storeCar.environmentEmissions || {};
300
+ const price = storeCar.price || {};
301
+
302
+ // --- price / monthly (REQUIRED) ---
303
+ // monthly ← price.financing.monthlyInstallment. This is the financing rate
304
+ // produced by FinancingStore via getComputedFinancing(config).financing
305
+ // (getFinancing.ts:82 `monthlyInstallment`), spread into price.financing by
306
+ // transformDataForVehicles (DataTransformers.ts:345). It is the LEAD price.
307
+ const monthly = num(price?.financing?.monthlyInstallment) ?? 0;
308
+ // price ← price.currentSalesPrice (DataTransformers.ts:352).
309
+ const purchase = num(price?.currentSalesPrice) ?? 0;
310
+
311
+ // --- rating (REQUIRED-WHEN-PRICED) ← real Preisbewertung ---
312
+ // BL-08 (P1, MONEY): getPriceRating(0, 0) mathematically resolves to tier 5
313
+ // ("Top Preis" — the BEST possible rating). Its internal min/max bands are all
314
+ // `predicted * (1 ± pct)`, which collapse to 0 when predicted is 0, and the
315
+ // topPrice branch checks `currentSalesPrice <= min` — 0 <= 0 is true. A
316
+ // missing/broken price payload must NEVER get dressed up as the best deal on
317
+ // the lot. Only compute/emit a rating when there is a real, positive sales
318
+ // price; otherwise rating/ratingLabel stay '' (falsy) — every consumer
319
+ // (CarCard.tsx, cardParts.tsx, FinanceCalculator.tsx) already treats a falsy
320
+ // rating as "no badge", so no type change is needed here.
321
+ const predicted =
322
+ purchase > 0 ? getPredictablePrice(purchase, num(price?.mlCurrentSalesPricePredicted) as number) : undefined;
323
+ const { rating, ratingLabel } = purchase > 0 ? mapRating(purchase, predicted) : { rating: '', ratingLabel: '' };
324
+
325
+ // --- key specs ---
326
+ const powerKW = num(engineData.powerKW);
327
+ const powerPS = num(engineData.powerPS);
328
+ const power = getPowerLabel(powerKW as number, powerPS as number); // "150 kW (204 PS)"
329
+
330
+ const regTs = num(info.regDate);
331
+ const reg = regTs ? formatTimestamp({ timestamp: regTs, format: 'MM/YYYY' }) : '';
332
+
333
+ const ownersN = num(info.numberOfPreviousOwners);
334
+
335
+ // --- EnVKV consumption line (REQUIRED on every German car ad) ---
336
+ // Prefer WLTP figures when present (the legacy cards do too), else NEDC.
337
+ const consVal = num(consumption.wltpCombined) ?? num(consumption.consumptionCombined);
338
+ const co2Val = num(emissions.wltpCo2) ?? num(emissions.co2);
339
+ const cons = consVal != null ? `${consVal.toLocaleString(localeTag(language))} l/100 km` : '';
340
+ const co2 = co2Val != null ? `${co2Val.toLocaleString(localeTag(language))} g/km` : '';
341
+ const co2class = co2ClassLetter(emissions.wltpEnergyEfficiencyClass);
342
+ const phev = buildPhev(storeCar, language);
343
+
344
+ // --- media ---
345
+ const gallery = buildGallery(storeCar, deps);
346
+ const photos = num(storeCar.imagesCount) ?? 0;
347
+
348
+ // --- optional: leasing rate — ONLY when leasing is actually active for this car.
349
+ // SearchResultsStore.getCarsForPage stamps price.leasing.isActive via getLeasingActive
350
+ // (car age + mileage within the leasing limits). Legacy SRP shows "Leasing ---" when
351
+ // inactive; we mirror that by leaving `lease` undefined so PricePaths omits the row
352
+ // (instead of computing/showing a leasing rate the car isn't eligible for).
353
+ const leasingActive = !!(price && price.leasing && price.leasing.isActive);
354
+ const lease = leasingActive ? num(price?.leasing?.monthlyInstallment) : undefined;
355
+
356
+ // --- optional: list price / savings — ONLY from a real strike price ---
357
+ // transformDataForVehicles exposes oldMonthlyInstallment / highestPrice via
358
+ // the financing spread, and price.historyPriceDifference. There is NO reliable
359
+ // purchase-price strike on the search payload today, so we leave listPrice /
360
+ // savings UNDEFINED unless a real highestPrice strike exists above the sale
361
+ // price. See fieldMapping.ts — flagged for backend confirmation.
362
+ const isStrikeShown = !!price?.financing?.isStrikeShown;
363
+ const highest = num(price?.financing?.highestPrice) ?? num(price?.highestPrice);
364
+ let listPrice: number | undefined;
365
+ let savings: number | undefined;
366
+ if (isStrikeShown && highest != null && purchase > 0 && highest > purchase) {
367
+ listPrice = highest;
368
+ savings = highest - purchase;
369
+ }
370
+
371
+ // --- price drop (REAL) — mirrors the legacy SRL green "−X €" badge: show the reduction only
372
+ // when price.historyPriceDifference is a meaningful amount (≥ 500 €, the legacy threshold).
373
+ const histDrop = num(price?.historyPriceDifference);
374
+ const drop = histDrop != null && histDrop >= 500 ? histDrop : undefined;
375
+ // percent reduction (historyPriceDifferencePerCent) — paired with `drop` for the −X% badge.
376
+ const histPct = num(price?.historyPriceDifferencePerCent);
377
+ const dropPct = drop != null && histPct != null && histPct > 0 ? Math.round(histPct) : undefined;
378
+
379
+ // --- NEU badge (REAL) — the legacy showNewLabel flag carried on the store car. ---
380
+ const isNew = !!storeCar.showNewLabel;
381
+
382
+ // --- availability (REAL) — offer.availabilityMode. 'always' → immediately available. ---
383
+ const offer = storeCar.offer && typeof storeCar.offer === 'object' ? storeCar.offer : {};
384
+ const availability =
385
+ offer.availabilityMode === 'selector_availabilityMode_always'
386
+ ? t
387
+ ? t('autobahn:availability.immediately')
388
+ : 'Sofort verfügbar'
389
+ : undefined;
390
+ // 0 € Anzahlung available — transform sets offer.showDownPayment = (raw showDownPayment && zero first installment).
391
+ const zeroDown = !!offer.showDownPayment;
392
+
393
+ // --- gallery activity strip (REAL) — UserActionsAPI 'stats/viewers', injected via deps.stats. ---
394
+ const viewsCount = num(deps.stats?.totalCarImpCount);
395
+ const favoritesCount = num(deps.stats?.totalFavCount);
396
+
397
+ const carView: AutobahnCar = {
398
+ // identity / headline
399
+ make: String(title.make ?? ''),
400
+ model: String(title.model ?? ''),
401
+ trim: String(title.subModel ?? ''),
402
+
403
+ // key specs
404
+ km: num(info.mileage) ?? 0,
405
+ reg,
406
+ power,
407
+ fuel: cbd(consumption.fuel, t),
408
+ gear: cbd(info.gearbox, t),
409
+ owners: ownersN ?? 0,
410
+
411
+ // price
412
+ monthly,
413
+ price: purchase,
414
+
415
+ // media
416
+ gallery,
417
+ photos,
418
+
419
+ // EnVKV
420
+ cons,
421
+ co2,
422
+ co2class: co2class || '',
423
+ ...(phev ? { phev } : {}),
424
+
425
+ // trust / features — equipment highlight chips (Matrix-LED, Virtual Cockpit, AHK, ACC, …).
426
+ // transformDataForVehicles extracted the present highlight selector-keys via getActualHighlights
427
+ // (reading the raw equipment categories); translate them to labels here (cbd → t('cbd:<key>')).
428
+ // First 4, like the design's card. Empty when the car has no notable equipment.
429
+ features: (Array.isArray((storeCar as any).highlights) ? (storeCar as any).highlights : [])
430
+ .map((k: any) => cbd(k, t))
431
+ .filter((s: string) => !!s)
432
+ .slice(0, 4),
433
+ rating,
434
+ ratingLabel,
435
+
436
+ // optional (only when real)
437
+ ...(listPrice != null ? { listPrice } : {}),
438
+ ...(savings != null ? { savings } : {}),
439
+ ...(lease != null ? { lease } : {}),
440
+ ...(drop != null ? { drop } : {}),
441
+ ...(dropPct != null ? { dropPct } : {}),
442
+ ...(zeroDown ? { zeroDown } : {}),
443
+ ...(isNew ? { isNew } : {}),
444
+ ...(availability ? { availability } : {}),
445
+ ...(viewsCount != null ? { viewsCount } : {}),
446
+ ...(favoritesCount != null ? { favoritesCount } : {}),
447
+
448
+ // NEEDS-DATA: deliberately omitted (marketLow, marketAvg, marketHigh, watchers, views).
449
+ // The cards render 'Daten folgt' for these until a real backend exists.
450
+ };
451
+
452
+ return carView;
453
+ }
454
+
455
+ export default toAutobahnCar;