@bytebrand/fe-ui-core 4.2.242 → 4.2.243

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 (34) hide show
  1. package/package.json +1 -1
  2. package/source/components/Checkout/CheckoutStepper/CheckoutStepper.styl +2 -190
  3. package/source/components/Checkout/OrderOverviewItem/OrderOverviewItem.styl +2 -2
  4. package/source/components/Checkout/OrderOverviewItem/OrderOverviewItem.tsx +3 -3
  5. package/source/components/InfoBlocks/FirstInfoBlock/FirstInfoBlockItem/FirstInfoBlockItem.styl +4 -6
  6. package/source/components/UserDashboardPage/sections/OrderStatusSection/AdditionalOrderInfo.styl +5 -1
  7. package/source/components/UserDashboardPage/sections/OrderStatusSection/AdditionalOrderInfo.tsx +1 -1
  8. package/source/components/UserDashboardPage/sections/OrderStatusSection/OrderStatusCar.tsx +43 -27
  9. package/source/components/UserDashboardPage/sections/OrderStatusSection/OrderStatusSection.tsx +62 -27
  10. package/source/components/VehicleDetailedSidebar/VehicleDetailedSidebar.styl +9 -1
  11. package/source/components/VehicleDetailedSidebar/VehicleDetailedSidebar.tsx +36 -32
  12. package/source/components/VehicleDetailedSidebar/partials/PriceContent.tsx +1 -1
  13. package/source/components/VehicleDetailedSlider/VehicleDetailedSlider.styl +45 -0
  14. package/source/components/VehicleDetailedSlider/VehicleDetailedSlider.tsx +112 -42
  15. package/source/components/VehicleDetailedSlider/partials/Stats.tsx +2 -2
  16. package/source/components/VehicleSmallCard/VehicleData/VechiclePriceItem/VechiclePriceItem.tsx +4 -2
  17. package/source/components/VehicleSmallCard/VehicleData/VehiclePrice/VehiclePrice.styl +35 -1
  18. package/source/components/VehicleSmallCard/VehicleData/VehiclePrice/VehiclePrice.tsx +8 -2
  19. package/source/components/VehicleSmallCard/VehicleData/VehicleTitle/VehicleTitle.styl +11 -2
  20. package/source/components/VehicleSmallCard/VehicleData/VehicleTitle/VehicleTitle.tsx +2 -1
  21. package/source/components/VehicleSmallCard/VehicleSmallCard.tsx +0 -1
  22. package/source/components/_common/Button/Button.tsx +4 -2
  23. package/source/components/_common/IconSVG/IconSVGConfig.tsx +2 -0
  24. package/source/components/_common/IconSVG/SVG/slider/YoutubeButton.tsx +26 -0
  25. package/source/components/_common/MaterialAutocomplete/MaterialAutocomplete.styled.tsx +8 -8
  26. package/source/components/_common/MaterialSelect/MaterialSelect.styled.tsx +4 -4
  27. package/source/components/_common/OfferRequestButtonWrapper/OfferRequestButtonWrapper.tsx +12 -4
  28. package/source/components/_common/withStats/withStats.styl +3 -0
  29. package/source/components/_common/withStats/withStats.tsx +18 -15
  30. package/source/components/containers/SearchPage/FiltersContainer/FiltersContainer.styl +3 -1
  31. package/source/components/containers/SearchPage/FiltersContainer/FiltersContainer.tsx +7 -7
  32. package/source/framework/types/types.ts +2 -0
  33. package/source/framework/utils/CommonUtils.ts +1 -0
  34. package/source/framework/utils/DateUtils.ts +8 -0
@@ -10,6 +10,7 @@ import styles from './VehicleDetailedSidebar.styl';
10
10
  import { vehicleProps } from '../../locales/data';
11
11
  import { IVehicleDetailedSidebarProps } from '../../framework/types/types';
12
12
  import DealerInfo from '../Alternative/DealerInfo';
13
+ import { Skeleton } from '@mui/material';
13
14
 
14
15
  declare global {
15
16
  interface Window {
@@ -35,7 +36,8 @@ const VehicleDetailedSidebar: FunctionComponent<IVehicleDetailedSidebarProps> =
35
36
  originUrl,
36
37
  // isAlternative,
37
38
  infoSections,
38
- onCurrentSalesPriceChange
39
+ onCurrentSalesPriceChange,
40
+ isFetching
39
41
  } = props;
40
42
  const ref = useRef(null);
41
43
  const [offerBlockOpen, setOfferBlockOpen] = useState(false);
@@ -145,34 +147,34 @@ const VehicleDetailedSidebar: FunctionComponent<IVehicleDetailedSidebarProps> =
145
147
 
146
148
  return (
147
149
  <>
148
- <div className={styles.detailedInfo}>
149
- <Title {...titleProps} />
150
- <Price {...priceProps} />
151
- <Price {...priceProps} isSticky={true} />
152
- {isMobileOnly && (
153
- <div
154
- ref={ref}
155
- data-locale='de-DE'
156
- data-template-id='5419b6a8b0d04a076446a9ad'
157
- data-businessunit-id='46edfd1c0000640005017f22'
158
- data-style-height='32px'
159
- data-style-width='100%'
160
- data-theme='light'
161
- data-style-alignment='center'
162
- >
163
- <a
164
- href='https://de.trustpilot.com/review/www.auto.de'
165
- target='_blank'
166
- rel='noopener noreferrer'
150
+ {!isFetching ? <div className={styles.detailedInfo}>
151
+ <Title {...titleProps} />
152
+ <Price {...priceProps} />
153
+ <Price {...priceProps} isSticky={true} />
154
+ {isMobileOnly && (
155
+ <div
156
+ ref={ref}
157
+ data-locale='de-DE'
158
+ data-template-id='5419b6a8b0d04a076446a9ad'
159
+ data-businessunit-id='46edfd1c0000640005017f22'
160
+ data-style-height='32px'
161
+ data-style-width='100%'
162
+ data-theme='light'
163
+ data-style-alignment='center'
167
164
  >
168
- Trustpilot
169
- </a>
170
- </div>
171
- )}
172
- {props.children}
173
- </div>
174
- <div>
175
- {isAlternativeType &&
165
+ <a
166
+ href='https://de.trustpilot.com/review/www.auto.de'
167
+ target='_blank'
168
+ rel='noopener noreferrer'
169
+ >
170
+ Trustpilot
171
+ </a>
172
+ </div>
173
+ )}
174
+ {props.children}
175
+ </div> : <div className={styles.skeletonInfoContainer}><Skeleton /></div>
176
+ }
177
+ {!isFetching ? <div>{isAlternativeType &&
176
178
  <DealerInfo
177
179
  t={t}
178
180
  infoSections={infoSections}
@@ -182,10 +184,12 @@ const VehicleDetailedSidebar: FunctionComponent<IVehicleDetailedSidebarProps> =
182
184
  currentSalesPrice={currentSalesPrice}
183
185
  onCurrentSalesPriceChange={onCurrentSalesPriceChange}
184
186
  />}
185
- </div>
186
- <Hidden xs sm md>
187
- <div className={`${styles.detailedInfo} ${styles.highlights}`}>{carLoaded && <Properties {...propertiesProps} />}</div>
188
- </Hidden>
187
+ </div> : <div className={styles.skeletonInfoContainer}><Skeleton /></div>
188
+ }
189
+ {!isFetching ? <Hidden xs sm md>
190
+ <div className={`${styles.detailedInfo} ${styles.highlights}`}>{carLoaded && <Properties {...propertiesProps} />}</div>
191
+ </Hidden> : <div className={styles.skeletonInfoContainer}><Skeleton /></div>
192
+ }
189
193
  </>
190
194
  );
191
195
  };
@@ -108,7 +108,7 @@ const PriceContent: React.FunctionComponent<IPriceContentProps> = ({
108
108
  className={styles.infoIcon}
109
109
  customDimensions
110
110
  />
111
- <span>{t('sidebar.adjustRate')}</span>
111
+ <span>{priceTabActiveIndex === 2 ? t('sidebar.serviceProducts') : t('sidebar.adjustRate')}</span>
112
112
  <IconSVG name='menuArrow' className={`${styles.arrowDownIcon} ${offerBlockOpen ? styles.arrowUpIcon : ''}`} customDimensions />
113
113
  </span>
114
114
  </span>
@@ -100,3 +100,48 @@
100
100
 
101
101
  .blurred
102
102
  filter: blur(3px)
103
+
104
+ .frame
105
+ aspect-ratio:4/3
106
+ height: auto;
107
+ border-radius: 10px;
108
+ display: block;
109
+ border: none;
110
+
111
+ .noYoutubeWrapper
112
+ margin: 82px auto 0;
113
+ width: 487px;
114
+ display: flex;
115
+ flex-direction: column;
116
+ align-items: center;
117
+ +media-phone-only()
118
+ margin: 40px auto 0;
119
+ width: 297px;
120
+
121
+ svg
122
+ +media-phone-only()
123
+ width: 79px;
124
+ height: 56px;
125
+
126
+ .youtubeCookiesText
127
+ font-size: 28px;
128
+ font-weight: 400;
129
+ line-height: 36px;
130
+ margin:62px 0px 54px;
131
+ display: block;
132
+ text-align: center;
133
+ +media-phone-only()
134
+ margin: 36px auto 39px;
135
+ font-size:17px;
136
+ line-height: 21px
137
+
138
+ .btn
139
+ height: 38px!important
140
+ +media-phone-only()
141
+ height: 30px!important
142
+ font-size:13px;
143
+
144
+ .btn:first-child
145
+ margin-right:22px!important
146
+ +media-phone-only()
147
+ margin-right:5px!important
@@ -13,31 +13,38 @@ import withMagnifyGlassImage from '../_common/MagnifyGlass/MagnifyGlass';
13
13
  import { IImage, IPrice, SliderType } from '../../framework/types/types';
14
14
  import { PLACEHOLDER_IMAGE_SMALL_URL } from '../../framework/constants/common';
15
15
  import { VehicleDetailedSliderTranslate } from '../../locales/data';
16
+ import SvgYoutubeButton from '../_common/IconSVG/SVG/slider/YoutubeButton';
17
+ import Button from '../_common/Button/Button';
18
+ import { updateCookieList } from '../../framework/utils/CommonUtils';
19
+
20
+
16
21
 
17
22
  import styles from './VehicleDetailedSlider.styl';
18
23
 
19
24
  interface IProps {
20
25
  t: (phrase: string, config?: any) => string;
21
26
  price: IPrice;
22
- photos: IImage [];
23
- exteriorPhotos: IImage [];
27
+ photos: IImage[];
28
+ exteriorPhotos: IImage[];
24
29
  interiorPhoto: IImage;
25
30
  mainImageUrl: string;
26
31
  mainImageBlur: boolean;
27
32
  statsData: any;
28
33
  isFavorite: boolean;
29
34
  showNewLabel: boolean;
30
- activeTab:number;
35
+ activeTab: number;
31
36
  make: string;
32
37
  model: string;
33
38
  subModel: string;
34
39
  powerKW: number;
35
40
  powerPS: number;
36
- financingConfig:any;
41
+ financingConfig: any;
42
+ youtubeId: string;
37
43
  showModal?: (id: string, props?: any) => void;
38
44
  hideModal: (id: string) => void;
39
45
  onCarFavorite: (event: MouseEvent<HTMLElement>) => void;
40
- showDownPayment:boolean;
46
+ showDownPayment: boolean;
47
+ handleSentryInit?: () => void;
41
48
  }
42
49
 
43
50
  interface IState {
@@ -46,6 +53,8 @@ interface IState {
46
53
  smallLoaded: boolean;
47
54
  largeLoaded1: boolean;
48
55
  largeLoaded01: boolean;
56
+ videoSrc: string;
57
+ showYoutube: boolean;
49
58
  }
50
59
 
51
60
  const MagnifyGlassImage = withMagnifyGlassImage(Image);
@@ -62,17 +71,21 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
62
71
  };
63
72
 
64
73
  private slider: any;
74
+
65
75
  private imagesCache: string[] = [];
66
76
 
67
77
  constructor(props: IProps) {
68
78
  super(props);
69
-
79
+ const cookieConfig = JSON.parse(localStorage.getItem('cookieConfig')) || {};
80
+ const youtubeConfig = !cookieConfig?.marketing?.includes('youtube');
70
81
  this.state = {
71
82
  activeSlide: 0,
72
83
  largeLoaded: false,
73
84
  smallLoaded: false,
74
85
  largeLoaded1: false,
75
- largeLoaded01: false
86
+ largeLoaded01: false,
87
+ videoSrc: '',
88
+ showYoutube: youtubeConfig
76
89
  };
77
90
  }
78
91
 
@@ -80,7 +93,11 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
80
93
  this.slider.slickGoTo(0);
81
94
  };
82
95
 
83
- componentDidUpdate(prevProps: IProps) {
96
+
97
+ componentDidUpdate(prevProps: IProps, prevState: IState) {
98
+ const cookieConfig = JSON.parse(localStorage.getItem('cookieConfig')) || {};
99
+ const showYoutube = !cookieConfig?.marketing?.includes('youtube');
100
+ console.log('showYoutube', showYoutube);
84
101
  if (prevProps.photos.length !== this.props.photos.length && this.props.photos.length === 0) {
85
102
  this.setState(() => ({
86
103
  largeLoaded: false,
@@ -89,10 +106,15 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
89
106
  largeLoaded01: false
90
107
  }));
91
108
  }
109
+ if (showYoutube !== prevState.showYoutube) {
110
+ this.setState(() => ({
111
+ showYoutube: showYoutube
112
+ }));
113
+ }
92
114
  }
93
115
 
94
116
  handleOpenSliderModal = (sliderType: SliderType) => {
95
- const { t = (phrase: string) => _get(VehicleDetailedSliderTranslate(statsData), phrase, phrase), photos, exteriorPhotos, interiorPhoto, showModal, hideModal, statsData } = this.props;
117
+ const { t = (phrase: string) => _get(VehicleDetailedSliderTranslate(statsData), phrase, phrase), photos, exteriorPhotos, interiorPhoto, showModal, hideModal, statsData, handleSentryInit } = this.props;
96
118
  const { activeSlide } = this.state;
97
119
 
98
120
  showModal('VEHICLE_DETAILED_SLIDER_MODAL', {
@@ -108,12 +130,22 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
108
130
  onClose: (index: number) => {
109
131
  this.slider.slickGoTo(index, true);
110
132
  hideModal('VEHICLE_DETAILED_SLIDER_MODAL');
111
- }
133
+ },
134
+ handleSentryInit: handleSentryInit
112
135
  });
113
136
  };
114
137
 
138
+ handleSlideChange = (_currentSlide: any, nextSlide: number) => {
139
+ const { photos } = this.props;
140
+ if (photos[nextSlide].videoUrl) {
141
+ this.setState({ videoSrc: `https://www.youtube.com/embed/${photos[nextSlide].videoUrl}` })
142
+ } else {
143
+ this.setState({ videoSrc: null })
144
+ }
145
+ }
146
+
115
147
  getImages = () => {
116
- const { photos, mainImageUrl, mainImageBlur } = this.props;
148
+ const { photos, mainImageUrl, mainImageBlur, t, handleSentryInit } = this.props;
117
149
  const { activeSlide, largeLoaded, smallLoaded, largeLoaded1, largeLoaded01 } = this.state;
118
150
 
119
151
  const imageProps = {
@@ -123,6 +155,7 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
123
155
  className: styles.image,
124
156
  withLoader: false
125
157
  };
158
+
126
159
  if (Array.isArray(photos) && photos.length > 0 && largeLoaded && smallLoaded && largeLoaded1 && largeLoaded01) {
127
160
  let isMouseDown = false;
128
161
  let isDragging = false;
@@ -147,11 +180,24 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
147
180
  isDragging = false;
148
181
  };
149
182
 
183
+ const updateCookies = () => {
184
+ const cookieConfig = localStorage.getItem('cookieConfig');
185
+ const conf = JSON.parse(cookieConfig);
186
+ const indexToRemove = conf.marketing.indexOf('youtube');
187
+ if (indexToRemove !== -1) {
188
+ conf.marketing.splice(indexToRemove, 1);
189
+ }
190
+ const showYoutube = !conf?.marketing?.includes('youtube');
191
+ this.setState({ showYoutube: showYoutube })
192
+ localStorage.setItem('cookieConfig', JSON.stringify(conf));
193
+ updateCookieList(handleSentryInit);
194
+ }
195
+
196
+
150
197
  const imagesCount = photos.length;
151
198
  const currentSlide = activeSlide;
152
199
  const prevSlide = (activeSlide - 1 % imagesCount + imagesCount) % imagesCount;
153
200
  const nextSlide = (activeSlide + 1 % imagesCount + imagesCount) % imagesCount;
154
-
155
201
  return photos.map((item: IImage, index: number) => {
156
202
  const showImage = index === currentSlide || index === prevSlide || index === nextSlide || this.imagesCache[index] !== undefined;
157
203
  const imageUrlSmall = _get(item, 'imageUrlSmall', null);
@@ -160,16 +206,15 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
160
206
  this.imagesCache[currentSlide] = imageUrlLarge;
161
207
  this.imagesCache[prevSlide] = imageUrlLarge;
162
208
  this.imagesCache[nextSlide] = imageUrlLarge;
163
-
164
209
  return (
165
210
  <div
166
211
  className={styles.photo}
167
212
  key={imageUrlLarge}
168
213
  onMouseDown={handleMouseDown}
169
214
  onMouseMove={handleMouseMove}
170
- onMouseUp={handleMouseUp}
215
+ onMouseUp={this.state.showYoutube ? handleMouseUp : null}
171
216
  >
172
- {showImage && (
217
+ {showImage && !item.videoUrl && (
173
218
  <MagnifyGlassImage
174
219
  src={index !== 0 ? imageUrlLarge : null}
175
220
  srcSmall={index === 0 ? imageUrlSmall : null}
@@ -177,54 +222,77 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
177
222
  {...imageProps}
178
223
  />
179
224
  )}
225
+ {showImage && item.videoUrl && this.state.showYoutube && (
226
+ <iframe
227
+ width='100%'
228
+ height='441'
229
+ src={this.state.videoSrc}
230
+ title='YouTube Video'
231
+ className={styles.frame}
232
+ ></iframe>
233
+ )}
234
+ {showImage && item.videoUrl && !this.state.showYoutube && this.state.videoSrc && (
235
+ <div className={styles.noYoutubeWrapper}>
236
+ <SvgYoutubeButton></SvgYoutubeButton>
237
+ <span className={styles.youtubeCookiesText}>{t('youtube.acceptCookiesText')}</span>
238
+ <div>
239
+ <Button variant='text' className={styles.btn} onClick={() => window.open('https://www.youtube.com/howyoutubeworks/our-commitments/protecting-user-data/', '_blank')}>
240
+ {t('youtube.dataProtection')}
241
+ </Button>
242
+ <Button color='primary' className={styles.btn} onClick={updateCookies}>{t('youtube.allow')}</Button>
243
+ </div>
244
+ </div>
245
+ )}
180
246
  </div>
181
247
  );
182
248
  });
183
249
  }
184
-
185
250
  if (mainImageUrl) {
186
251
  const imagesCount = Array.isArray(photos) && photos.length > 0 ? photos.length : 0;
187
252
  const prevSlide = (activeSlide - 1 % imagesCount + imagesCount) % imagesCount;
188
253
  const nextSlide = (activeSlide + 1 % imagesCount + imagesCount) % imagesCount;
189
254
  return (
190
255
  // preload cached photos from props
256
+
191
257
  <div className={classnames(styles.photo, { [styles.blurred]: (mainImageBlur && mainImageUrl !== PLACEHOLDER_IMAGE_SMALL_URL) })} key={mainImageUrl}>
192
- {(!largeLoaded || !smallLoaded || !largeLoaded1 || !largeLoaded01) && <Image src={mainImageUrl} {...imageProps} /> }
258
+ {(!largeLoaded || !smallLoaded || !largeLoaded1 || !largeLoaded01) && <Image src={mainImageUrl} {...imageProps} />}
193
259
 
194
- { Array.isArray(photos) && photos.length > 0 && <Image
195
- style={ { display: 'none' } }
196
- src={ photos[activeSlide].imageUrlSmall }
197
- onLoad={ () => this.setState({ smallLoaded: true }) }
260
+ {Array.isArray(photos) && photos.length > 0 && <Image
261
+ style={{ display: 'none' }}
262
+ src={photos[activeSlide]?.imageUrlSmall}
263
+ onLoad={() => this.setState({ smallLoaded: true })}
198
264
  {...imageProps}
199
- />
265
+ />
200
266
  }
201
- { Array.isArray(photos) && photos.length > 0 && <Image
202
- style={ { display: 'none' } }
203
- src={ photos[activeSlide].imageUrlLarge }
204
- onLoad={ () => this.setState({ largeLoaded: true }) }
267
+ {Array.isArray(photos) && photos.length > 0 && <Image
268
+ style={{ display: 'none' }}
269
+ src={photos[activeSlide]?.imageUrlLarge}
270
+ onLoad={() => this.setState({ largeLoaded: true })}
205
271
  {...imageProps}
206
- />
272
+ />
207
273
  }
208
- { Array.isArray(photos) && photos.length > 0 && <Image
209
- style={ { display: 'none' } }
210
- src={ photos[nextSlide].imageUrlLarge }
211
- onLoad={ () => this.setState({ largeLoaded1: true }) }
274
+
275
+ {Array.isArray(photos) && photos.length > 0 && <Image
276
+ style={{ display: 'none' }}
277
+ src={photos[nextSlide]?.imageUrlLarge}
278
+ onLoad={() => this.setState({ largeLoaded1: true })}
212
279
  {...imageProps}
213
- />
280
+ />
214
281
  }
215
- { Array.isArray(photos) && photos.length > 0 && <Image
216
- style={ { display: 'none' } }
217
- src={ photos[prevSlide].imageUrlLarge }
218
- onLoad={ () => this.setState({ largeLoaded01: true }) }
282
+ {Array.isArray(photos) && photos.length > 0 && <Image
283
+ style={{ display: 'none' }}
284
+ src={photos[prevSlide]?.imageUrlLarge}
285
+ onLoad={() => this.setState({ largeLoaded01: true })}
219
286
  {...imageProps}
220
- />
287
+ />
221
288
  }
222
289
  </div>
223
290
  );
291
+
224
292
  }
225
293
 
226
294
  return (
227
- <div className={styles.noPhoto}/>
295
+ <div className={styles.noPhoto} />
228
296
  );
229
297
  };
230
298
 
@@ -249,7 +317,6 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
249
317
  onCarFavorite
250
318
  } = this.props;
251
319
  const { activeSlide } = this.state;
252
-
253
320
  const sliderProps = {
254
321
  autoPlay: false,
255
322
  speed: 300,
@@ -258,6 +325,7 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
258
325
  arrows: Array.isArray(photos) && photos.length > 0,
259
326
  slidesToShow: 1,
260
327
  slidesToScroll: 1,
328
+ beforeChange: this.handleSlideChange,
261
329
  afterChange: (index: number) => {
262
330
  this.setState({
263
331
  activeSlide: index
@@ -290,14 +358,16 @@ class VehicleDetailedSlider extends Component<IProps, IState> {
290
358
  return (
291
359
  <div className={styles.sliderWrap}>
292
360
  {isMobileOnly &&
293
- <Title {...{ t, make, model, subModel, powerKW, powerPS, onCarFavorite, isFavorite }}/>
361
+ <Title {...{ t, make, model, subModel, powerKW, powerPS, onCarFavorite, isFavorite }} />
294
362
  }
295
363
  <div className={styles.slider}>
296
- <PriceData {...priceProps}/>
364
+ {!photos[activeSlide]?.videoUrl && <PriceData {...priceProps} />}
297
365
  <Slider ref={slider => (this.slider = slider)} {...sliderProps}>
298
366
  {this.getImages()}
299
367
  </Slider>
300
- {isMobileOnly ? <MobileStats {...statsProps} /> : <Stats {...statsProps}/>}
368
+ {!photos[activeSlide]?.videoUrl ? (
369
+ isMobileOnly ? <MobileStats {...statsProps} /> : <Stats {...statsProps} />
370
+ ) : null}
301
371
  </div>
302
372
  </div>
303
373
  );
@@ -43,7 +43,7 @@ const Stats: FunctionComponent<IProps> = (props) => {
43
43
  </div>
44
44
  )}
45
45
  </div>
46
- <div className={styles.statsContainer}>
46
+ {(totalCarImpCount > 0 || totalFavCount > 0) && <div className={styles.statsContainer}>
47
47
  {totalCarImpCount > 0 && (
48
48
  <div className={`${styles.statsBlock} ${styles.saveCarAsFavorites}`}>
49
49
  <span>{t('slider.customersLookingTheCar', { count: totalCarImpCount })}</span>
@@ -54,7 +54,7 @@ const Stats: FunctionComponent<IProps> = (props) => {
54
54
  <span>{t('slider.saveCarAsFavorites', { count: totalFavCount })}</span>
55
55
  </div>
56
56
  )}
57
- </div>
57
+ </div>}
58
58
  </div>
59
59
  );
60
60
  };
@@ -36,6 +36,7 @@ export interface IVehiclePriceItemProps {
36
36
  combineRefAlternative?: boolean;
37
37
  postfix?: string;
38
38
  margin?: number;
39
+ isMarge?: boolean;
39
40
  }
40
41
  class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
41
42
  routeToActiveTab = () => {
@@ -70,7 +71,8 @@ class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
70
71
  showAboIcon = false,
71
72
  isPriceDisable = false,
72
73
  isNewPriceCategory = false,
73
- isStrikeShown = false
74
+ isStrikeShown = false,
75
+ isMarge
74
76
  } = this.props;
75
77
 
76
78
  const stylesItem = classnames(
@@ -150,7 +152,7 @@ class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
150
152
  <span className={styles.noPrice}>---</span>
151
153
  )}
152
154
 
153
- {isStrikeShown && isTotal && (
155
+ {isStrikeShown && isTotal && !isMarge && (
154
156
  <VehicleFormattedPrice
155
157
  numbersAfterDot={0}
156
158
  className={styles.oldPrice}
@@ -127,4 +127,38 @@
127
127
  margin-right: 5px;
128
128
 
129
129
  +media-tablet-landscape-up()
130
- margin-right: 10px;
130
+ margin-right: 10px;
131
+
132
+
133
+ .landingButton
134
+ position: relative;
135
+ padding: 0px 10px;
136
+ background-color: transparent;
137
+ border-radius: 4px;
138
+ color: #005ccb;
139
+ border: 1px solid #666CFF80;
140
+ font-size: 16px;
141
+ cursor: pointer;
142
+ overflow: hidden;
143
+ z-index: 0;
144
+
145
+ .landingButton::before
146
+ content: "";
147
+ position: absolute;
148
+ top: 50%;
149
+ left: 50%;
150
+ transform: translate(-50%, -50%);
151
+ width: 30%;
152
+ height: 100%;
153
+ background-color: #82b1ff91;
154
+ border-radius: 20%;
155
+ opacity: 0;
156
+ transition: width 0.7s ease-out, height 0.7s ease-out, opacity 0.7s ease-out;
157
+ z-index: -1;
158
+
159
+
160
+ .landingButton:active::before
161
+ width: 200%;
162
+ height: 200%;
163
+ opacity: 1;
164
+ transition: width 0.7s ease-out, height 0.7s ease-out, opacity 0.7s ease-out;
@@ -136,6 +136,7 @@ const VehiclePrice: React.FC<IVehiclePriceSectionProps> = (props: IVehiclePriceS
136
136
  const buttonClassNames = classnames(
137
137
  classButton,
138
138
  styles.buttonDetails,
139
+ { [styles.landingButton]: vehicleComponentName === 'landing' },
139
140
  { [styles.isAlternativeButton]: typeAlternative }
140
141
  );
141
142
 
@@ -195,7 +196,8 @@ const VehiclePrice: React.FC<IVehiclePriceSectionProps> = (props: IVehiclePriceS
195
196
  {
196
197
  isTotal: true,
197
198
  totalCurrent: margin ? margin : currentSalesPriceExtra,
198
- title: t('vehicleProps:title.marge')
199
+ title: t('vehicleProps:title.marge'),
200
+ isMarge: true
199
201
  }
200
202
  ] : [
201
203
  ...priceItemsGlobal,
@@ -254,6 +256,7 @@ const VehiclePrice: React.FC<IVehiclePriceSectionProps> = (props: IVehiclePriceS
254
256
  routeObj={routeObj}
255
257
  vehicleComponentName={vehicleComponentName}
256
258
  combineRefAlternative={combineRefAlternative}
259
+ isMarge={props.isMarge}
257
260
  />
258
261
  ))}
259
262
  {vehicleComponentName === 'favorite' && showCompareCheckboxes && (
@@ -273,7 +276,10 @@ const VehiclePrice: React.FC<IVehiclePriceSectionProps> = (props: IVehiclePriceS
273
276
  </Button>
274
277
  ) : null}
275
278
  {showOfferBtn ? (
276
- <Button variant={offerBtnVariantCondition} className={buttonClassNames} onClick={onDetailsClick}>{t('vehicleProps:title.toOffer')}</Button>
279
+ vehicleComponentName === 'landing' ? (
280
+ <button className={buttonClassNames} onClick={onDetailsClick}>{t('vehicleProps:title.toOffer')}</button>
281
+ ) :
282
+ <Button variant={offerBtnVariantCondition} className={buttonClassNames} onClick={onDetailsClick}>{t('vehicleProps:title.toOffer')}</Button>
277
283
  ) : ''}
278
284
  </section>
279
285
  );
@@ -28,6 +28,9 @@
28
28
  display block
29
29
  +media-tablet-landscape-up()
30
30
  display flex
31
+ &.wrapTitlesAlternative
32
+ +media-tablet-landscape-up()
33
+ flex-wrap: wrap
31
34
  &.wrapTitlesFavorite
32
35
  display: flex;
33
36
  +media-tablet-landscape-up()
@@ -57,7 +60,7 @@
57
60
 
58
61
  +media-tablet-landscape-up()
59
62
  margin: 0 0 -1px 3px
60
- max-width: 100%;
63
+ overflow: hidden
61
64
 
62
65
  .optionTitle
63
66
  display: flex
@@ -72,6 +75,7 @@
72
75
  margin-top: 3px;
73
76
  +media-tablet-landscape-up()
74
77
  margin-left: 8px;
78
+ width: 100%
75
79
  margin-top: 0;
76
80
  &.optionTitleFavorite
77
81
  font-size: 12px;
@@ -83,7 +87,12 @@
83
87
  margin-left: 8px;
84
88
  &.optionTitleIsAlternative
85
89
  overflow: hidden;
86
- max-width: 260px;
90
+ .subModel
91
+ margin: 5px 0 0 0
92
+ +media-tablet-landscape-up()
93
+ max-width: 260px;
94
+ +media-tablet-landscape-up()
95
+ margin-left: 0
87
96
 
88
97
  .sponsored
89
98
  font-weight: 700
@@ -33,7 +33,8 @@ const VehicleTitle: React.FC<IVehicleTitleProps> = ({
33
33
  styles.wrapTitles,
34
34
  { [styles.wrapTitlesFavorite]: vehicleComponentName === 'favorite' },
35
35
  { [styles.wrapTitlesRecently]: vehicleComponentName === 'recently' || vehicleComponentName === 'landing' || vehicleComponentName === 'main' },
36
- { [styles.wrapTitlesSearch]: vehicleComponentName === 'search' || vehicleComponentName === 'myVehicles' }
36
+ { [styles.wrapTitlesSearch]: vehicleComponentName === 'search' || vehicleComponentName === 'myVehicles' },
37
+ { [styles.wrapTitlesAlternative]: combineRefAlternative }
37
38
  );
38
39
  const optionTitleClassName = classnames(
39
40
  styles.optionTitle,
@@ -34,7 +34,6 @@ interface IVehicleSmallCardProps {
34
34
  language?: string;
35
35
  vehicleComponentName?: 'comparable' | 'landing' | 'search' | 'main' | 'myVehicles' | 'favorite' | 'recently';
36
36
  isTop?: boolean;
37
- isDealer?: boolean;
38
37
  isDealerSuperAdmin?: boolean;
39
38
  isReferenceSearch?: boolean;
40
39
  dashboardButtonText?: string;