@bytebrand/fe-ui-core-autobahn 1.0.134 → 1.0.135
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.
- package/cards/CarCard.tsx +5 -19
- package/cards/CarRow.tsx +7 -20
- package/cards/cardParts.tsx +22 -55
- package/cards/types.ts +0 -10
- package/compat/VehicleSmallCard/VehicleData/VechiclePriceItem/VechiclePriceItem.tsx +6 -3
- package/compat/VehicleSmallCard/VehicleData/VehicleInfo/VehicleInfo.tsx +2 -2
- package/compat/VehicleSmallCard/VehicleSmallCard.tsx +4 -6
- package/data/toAutobahnCar.ts +0 -24
- package/package.json +1 -1
- package/vdp/VdpModules.tsx +3 -9
package/cards/CarCard.tsx
CHANGED
|
@@ -51,14 +51,8 @@ export interface CarCardProps {
|
|
|
51
51
|
isFavorite: boolean;
|
|
52
52
|
/** toggle the favorite; the heart calls this (click is kept off the card). */
|
|
53
53
|
onToggleFavorite: () => void;
|
|
54
|
-
/** fired when the card is clicked (opens the detail page).
|
|
55
|
-
|
|
56
|
-
* `?mode=` query flag so the originating card and the CDP always agree on the product. */
|
|
57
|
-
onOpen: (car: AutobahnCar, mode?: PaymentMode) => void;
|
|
58
|
-
/** ADV-181 — fired when the user explicitly switches the card's payment tab. Pages use it to
|
|
59
|
-
* persist the per-car product choice (FinancingStore.setSelectedProduct) + analytics. The
|
|
60
|
-
* card still owns the visual tab state; this is a notification, not a controlled input. */
|
|
61
|
-
onModeChange?: (mode: PaymentMode) => void;
|
|
54
|
+
/** fired when the card is clicked (opens the detail page). */
|
|
55
|
+
onOpen: (car: AutobahnCar) => void;
|
|
62
56
|
/** fired on first hover/touch of the media box — the SRP uses it to lazy-load the gallery. */
|
|
63
57
|
onMediaEnter?: () => void;
|
|
64
58
|
/**
|
|
@@ -119,16 +113,8 @@ const CarCard: React.FunctionComponent<CarCardProps> = ({
|
|
|
119
113
|
onCall,
|
|
120
114
|
onOpenRateAdjust,
|
|
121
115
|
onShowFinancingDetails,
|
|
122
|
-
onModeChange,
|
|
123
116
|
}) => {
|
|
124
|
-
|
|
125
|
-
// financing vs leasing, or the user's saved per-car choice) — computed by toAutobahnCar,
|
|
126
|
-
// so SSR/hydration agree. Absent (older producer) → financing, the pre-ADV-181 default.
|
|
127
|
-
const [mode, setMode] = useState<PaymentMode>(car.defaultMode ?? 'financing');
|
|
128
|
-
const changeMode = (m: PaymentMode) => {
|
|
129
|
-
setMode(m);
|
|
130
|
-
onModeChange && onModeChange(m);
|
|
131
|
-
};
|
|
117
|
+
const [mode, setMode] = useState<PaymentMode>('financing');
|
|
132
118
|
const [photoIndex, setPhotoIndex] = useState(0);
|
|
133
119
|
const [viewerOpen, setViewerOpen] = useState(false);
|
|
134
120
|
const mediaRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -174,7 +160,7 @@ const CarCard: React.FunctionComponent<CarCardProps> = ({
|
|
|
174
160
|
return (
|
|
175
161
|
<article
|
|
176
162
|
className="mcard mcard--interactive cc-card"
|
|
177
|
-
onClick={() => onOpen(car
|
|
163
|
+
onClick={() => onOpen(car)}
|
|
178
164
|
style={{ display: 'flex', flexDirection: 'column' }}
|
|
179
165
|
>
|
|
180
166
|
<div
|
|
@@ -289,7 +275,7 @@ const CarCard: React.FunctionComponent<CarCardProps> = ({
|
|
|
289
275
|
</div>
|
|
290
276
|
<SpecLine items={cardSpec(car)} oneLine />
|
|
291
277
|
<div className="cc-price" style={{ marginTop: 0, borderTop: '1px solid var(--md-outline-variant)' }}>
|
|
292
|
-
<PriceTabs car={car} mode={mode} onModeChange={
|
|
278
|
+
<PriceTabs car={car} mode={mode} onModeChange={setMode} t={t} />
|
|
293
279
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, marginTop: 10 }}>
|
|
294
280
|
<PriceHero car={car} mode={mode} t={t} alwaysShowUnit />
|
|
295
281
|
<PriceEvalCol car={car} t={t} />
|
package/cards/CarRow.tsx
CHANGED
|
@@ -52,13 +52,8 @@ export interface CarRowProps {
|
|
|
52
52
|
isFavorite: boolean;
|
|
53
53
|
/** toggle the favorite; the hearts call this (click is kept off the card). */
|
|
54
54
|
onToggleFavorite: () => void;
|
|
55
|
-
/** fired when the card (or the CTA) is clicked (opens the detail page).
|
|
56
|
-
|
|
57
|
-
* the VDP via `?mode=` so the originating card and the CDP always agree on the product. */
|
|
58
|
-
onOpen: (car: AutobahnCar, mode?: PaymentMode) => void;
|
|
59
|
-
/** ADV-181 — fired when the user explicitly switches the mobile payment tab. Pages use it to
|
|
60
|
-
* persist the per-car product choice (FinancingStore.setSelectedProduct) + analytics. */
|
|
61
|
-
onModeChange?: (mode: PaymentMode) => void;
|
|
55
|
+
/** fired when the card (or the CTA) is clicked (opens the detail page). */
|
|
56
|
+
onOpen: (car: AutobahnCar) => void;
|
|
62
57
|
/** fired on first hover/touch of the media box — the SRP uses it to lazy-load the gallery. */
|
|
63
58
|
onMediaEnter?: () => void;
|
|
64
59
|
/**
|
|
@@ -97,16 +92,8 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
|
|
|
97
92
|
t,
|
|
98
93
|
adminAction,
|
|
99
94
|
onShowFinancingDetails,
|
|
100
|
-
onModeChange,
|
|
101
95
|
}) => {
|
|
102
|
-
|
|
103
|
-
// Drives the mobile tab switcher AND the mode reported to onOpen; the desktop branch's
|
|
104
|
-
// untabbed PricePaths reads car.defaultMode directly.
|
|
105
|
-
const [mode, setMode] = useState<PaymentMode>(car.defaultMode ?? 'financing');
|
|
106
|
-
const changeMode = (m: PaymentMode) => {
|
|
107
|
-
setMode(m);
|
|
108
|
-
onModeChange && onModeChange(m);
|
|
109
|
-
};
|
|
96
|
+
const [mode, setMode] = useState<PaymentMode>('financing');
|
|
110
97
|
const [photoIndex, setPhotoIndex] = useState(0);
|
|
111
98
|
const mediaRef = useRef<HTMLDivElement | null>(null);
|
|
112
99
|
// always call the LATEST onMediaEnter without re-arming the observer on every render (the
|
|
@@ -159,7 +146,7 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
|
|
|
159
146
|
return (
|
|
160
147
|
<article
|
|
161
148
|
className="mcard mcard--interactive listcard"
|
|
162
|
-
onClick={() => onOpen(car
|
|
149
|
+
onClick={() => onOpen(car)}
|
|
163
150
|
style={{ background: 'var(--md-sc-lowest)' }}
|
|
164
151
|
>
|
|
165
152
|
<div className="listcard-media" ref={mediaRef} style={{ position: 'relative' }} onMouseEnter={onMediaEnter} onTouchStart={onMediaEnter}>
|
|
@@ -281,7 +268,7 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
|
|
|
281
268
|
the previously-unused PricePaths/PriceKauf pair. Both variants share the same
|
|
282
269
|
Preisbewertung meter + CTA, anchored to the bottom (margin-top:auto on .pp-purchase). */}
|
|
283
270
|
<div className="listcard-price">
|
|
284
|
-
<PriceTabs car={car} mode={mode} onModeChange={
|
|
271
|
+
<PriceTabs car={car} mode={mode} onModeChange={setMode} t={t} className="show-mobile" />
|
|
285
272
|
<div className="pp-purchase show-mobile">
|
|
286
273
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
|
|
287
274
|
<PriceHero car={car} mode={mode} t={t} alwaysShowUnit />
|
|
@@ -300,7 +287,7 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
|
|
|
300
287
|
iconRight="arrow-right"
|
|
301
288
|
onClick={(e) => {
|
|
302
289
|
e.stopPropagation();
|
|
303
|
-
onOpen(car
|
|
290
|
+
onOpen(car);
|
|
304
291
|
}}
|
|
305
292
|
>
|
|
306
293
|
{t('autobahn:card.cta.viewOffer')}
|
|
@@ -349,7 +336,7 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
|
|
|
349
336
|
iconRight="arrow-right"
|
|
350
337
|
onClick={(e) => {
|
|
351
338
|
e.stopPropagation();
|
|
352
|
-
onOpen(car
|
|
339
|
+
onOpen(car);
|
|
353
340
|
}}
|
|
354
341
|
>
|
|
355
342
|
{t('autobahn:card.cta.viewOffer')}
|
package/cards/cardParts.tsx
CHANGED
|
@@ -1103,11 +1103,6 @@ const PpRow: React.FunctionComponent<PpRowProps> = ({ label, value, unit, old, f
|
|
|
1103
1103
|
*/
|
|
1104
1104
|
export const PricePaths: React.FunctionComponent<PricePathsProps> = ({ car, t, className, onShowDetails }) => {
|
|
1105
1105
|
const hasLease = car.lease != null;
|
|
1106
|
-
// ADV-181: the hero rate follows the centrally-selected default product (cheaper valid rate,
|
|
1107
|
-
// computed in toAutobahnCar). Leasing leads only when it actually won AND is displayable;
|
|
1108
|
-
// 'buy'/absent both fall back to the financing hero (pre-ADV-181 layout) — the purchase price
|
|
1109
|
-
// keeps its own PriceKauf row below either way, per the desktop rate-first rule.
|
|
1110
|
-
const heroMode: PaymentMode = car.defaultMode === 'leasing' && hasLease ? 'leasing' : 'financing';
|
|
1111
1106
|
// Terms of the config the displayed rate was actually computed with (per-car:
|
|
1112
1107
|
// dealer rate + the user's saved localStorage adjustments) — default config
|
|
1113
1108
|
// terms only when the car doesn't carry its own.
|
|
@@ -1135,70 +1130,42 @@ export const PricePaths: React.FunctionComponent<PricePathsProps> = ({ car, t, c
|
|
|
1135
1130
|
) : (
|
|
1136
1131
|
<span className="pp-details-link">{t('autobahn:card.price.details')}</span>
|
|
1137
1132
|
);
|
|
1138
|
-
const finTermsLine = (
|
|
1139
|
-
<>
|
|
1140
|
-
{t('autobahn:card.price.financeTerms', {
|
|
1141
|
-
firstInstallment: finFirstInstallment,
|
|
1142
|
-
months: finMonths,
|
|
1143
|
-
count: finMonths,
|
|
1144
|
-
})}{' '}
|
|
1145
|
-
· {detailsLink('financing')}
|
|
1146
|
-
</>
|
|
1147
|
-
);
|
|
1148
|
-
const leasCompactTerms = hasLeasTerms && (
|
|
1149
|
-
<div className="pp-sub-terms">
|
|
1150
|
-
{/* dedicated keys (not a rework of leaseTerms) so mobile/VDP's own reviewed
|
|
1151
|
-
wording there stays untouched, but includes the same Sonderzahlung figure.
|
|
1152
|
-
Split across two lines with an explicit <br/> (column is too narrow for all
|
|
1153
|
-
three figures + Details on one line) — forced right after km/Jahr so "36" and
|
|
1154
|
-
"Mon." always land on the same line instead of an awkward mid-number wrap. */}
|
|
1155
|
-
{t('autobahn:card.price.leaseTermsCompactLine1', {
|
|
1156
|
-
firstInstallment: leasFirstInstallment,
|
|
1157
|
-
mileage: leasMileageStr,
|
|
1158
|
-
})}{' · '}
|
|
1159
|
-
<br />
|
|
1160
|
-
{t('autobahn:card.price.leaseTermsCompactLine2', { months: leasMonths })}{' '}
|
|
1161
|
-
· {detailsLink('leasing')}
|
|
1162
|
-
</div>
|
|
1163
|
-
);
|
|
1164
1133
|
return (
|
|
1165
1134
|
<div className={'pricepaths' + (className ? ' ' + className : '')}>
|
|
1166
|
-
<div className="pp-eyebrow">
|
|
1167
|
-
|
|
1168
|
-
</div>
|
|
1169
|
-
{/* reuses PriceHero's own rendering — the exact same stacked "UVP-Rate ⓘ /
|
|
1135
|
+
<div className="pp-eyebrow">{t('autobahn:card.price.financingFrom')}</div>
|
|
1136
|
+
{/* reuses PriceHero's own financing rendering — the exact same stacked "UVP-Rate ⓘ /
|
|
1170
1137
|
struck price / mtl." group beside the rate that .cc-price and mobile's tab switcher
|
|
1171
1138
|
already use, so the rate + unit never fight for room in one flat row (the earlier
|
|
1172
1139
|
hand-rolled version here put them side by side and wrapped for any 4+-digit rate). */}
|
|
1173
|
-
<PriceHero car={car} mode=
|
|
1174
|
-
|
|
1175
|
-
|
|
1140
|
+
<PriceHero car={car} mode="financing" t={t} alwaysShowUnit />
|
|
1141
|
+
<div className="pp-hero-terms">
|
|
1142
|
+
{t('autobahn:card.price.financeTerms', {
|
|
1143
|
+
firstInstallment: finFirstInstallment,
|
|
1144
|
+
months: finMonths,
|
|
1145
|
+
count: finMonths,
|
|
1146
|
+
})}{' '}
|
|
1147
|
+
· {detailsLink('financing')}
|
|
1148
|
+
</div>
|
|
1149
|
+
{hasLease && (
|
|
1150
|
+
<div className="pp-lease-row">
|
|
1151
|
+
<PpRow label={t('autobahn:card.price.leasing')} value={car.lease as number} unit="mtl." t={t} />
|
|
1176
1152
|
{hasLeasTerms && (
|
|
1177
|
-
<div className="pp-
|
|
1153
|
+
<div className="pp-sub-terms">
|
|
1154
|
+
{/* dedicated keys (not a rework of leaseTerms) so mobile/VDP's own reviewed
|
|
1155
|
+
wording there stays untouched, but includes the same Sonderzahlung figure.
|
|
1156
|
+
Split across two lines with an explicit <br/> (column is too narrow for all
|
|
1157
|
+
three figures + Details on one line) — forced right after km/Jahr so "36" and
|
|
1158
|
+
"Mon." always land on the same line instead of an awkward mid-number wrap. */}
|
|
1178
1159
|
{t('autobahn:card.price.leaseTermsCompactLine1', {
|
|
1179
1160
|
firstInstallment: leasFirstInstallment,
|
|
1180
1161
|
mileage: leasMileageStr,
|
|
1181
1162
|
})}{' · '}
|
|
1163
|
+
<br />
|
|
1182
1164
|
{t('autobahn:card.price.leaseTermsCompactLine2', { months: leasMonths })}{' '}
|
|
1183
1165
|
· {detailsLink('leasing')}
|
|
1184
1166
|
</div>
|
|
1185
1167
|
)}
|
|
1186
|
-
|
|
1187
|
-
<div className="pp-lease-row">
|
|
1188
|
-
<PpRow label={t('autobahn:finance.mode.financing')} value={car.monthly} unit="mtl." t={t} />
|
|
1189
|
-
<div className="pp-sub-terms">{finTermsLine}</div>
|
|
1190
|
-
</div>
|
|
1191
|
-
</>
|
|
1192
|
-
) : (
|
|
1193
|
-
<>
|
|
1194
|
-
<div className="pp-hero-terms">{finTermsLine}</div>
|
|
1195
|
-
{hasLease && (
|
|
1196
|
-
<div className="pp-lease-row">
|
|
1197
|
-
<PpRow label={t('autobahn:card.price.leasing')} value={car.lease as number} unit="mtl." t={t} />
|
|
1198
|
-
{leasCompactTerms}
|
|
1199
|
-
</div>
|
|
1200
|
-
)}
|
|
1201
|
-
</>
|
|
1168
|
+
</div>
|
|
1202
1169
|
)}
|
|
1203
1170
|
</div>
|
|
1204
1171
|
);
|
package/cards/types.ts
CHANGED
|
@@ -57,16 +57,6 @@ export interface AutobahnCar {
|
|
|
57
57
|
// --- price (always real) ---
|
|
58
58
|
/** financing monthly rate in EUR — the LEAD price on every card. */
|
|
59
59
|
monthly: number;
|
|
60
|
-
/**
|
|
61
|
-
* ADV-181 — which payment product leads on this card. Computed centrally by
|
|
62
|
-
* toAutobahnCar via fe-financing's pickDefaultProduct (cheaper valid rate of
|
|
63
|
-
* financing vs leasing; tie → financing; neither valid → 'buy'), then
|
|
64
|
-
* overridden by the user's saved explicit per-car selection when the fe-main
|
|
65
|
-
* transform stamped one (storeCar.selectedProduct). Cards initialise their
|
|
66
|
-
* tab state from this; absent (older producer) → 'financing', the pre-ADV-181
|
|
67
|
-
* behavior. Derived purely from card data, so SSR and hydration agree.
|
|
68
|
-
*/
|
|
69
|
-
defaultMode?: 'financing' | 'leasing' | 'buy';
|
|
70
60
|
/**
|
|
71
61
|
* financing terms the `monthly` rate was computed with — the per-car merged
|
|
72
62
|
* config (dealer rate + the user's saved localStorage adjustments, ADV-157).
|
|
@@ -39,9 +39,10 @@ export interface IVehiclePriceItemProps {
|
|
|
39
39
|
isMarge?: boolean;
|
|
40
40
|
}
|
|
41
41
|
class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
routeToActiveTab = () => {
|
|
43
|
+
const { priceTitle } = this.props;
|
|
44
|
+
localStorage.setItem('activeTabCDP', priceTitle);
|
|
45
|
+
}
|
|
45
46
|
|
|
46
47
|
render(): React.ReactNode {
|
|
47
48
|
const {
|
|
@@ -102,6 +103,7 @@ class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
|
|
|
102
103
|
...routeObj,
|
|
103
104
|
target,
|
|
104
105
|
rel,
|
|
106
|
+
onClick: this.routeToActiveTab,
|
|
105
107
|
className: priceItemCategoryClassName,
|
|
106
108
|
href: url
|
|
107
109
|
})}
|
|
@@ -186,6 +188,7 @@ class VehiclePriceItem extends React.Component<IVehiclePriceItemProps> {
|
|
|
186
188
|
...routeObj,
|
|
187
189
|
target,
|
|
188
190
|
rel,
|
|
191
|
+
onClick: this.routeToActiveTab,
|
|
189
192
|
className: styles.priceItemPrice,
|
|
190
193
|
href: url
|
|
191
194
|
})}
|
|
@@ -166,8 +166,8 @@ const VehicleInfo: React.FC<IVehicleInfoProps> = (props) => {
|
|
|
166
166
|
),
|
|
167
167
|
...routeObj,
|
|
168
168
|
className: wrapClasses,
|
|
169
|
-
// ADV-
|
|
170
|
-
|
|
169
|
+
// ADV-116: opening a CDP from a card defaults to the Financing tab.
|
|
170
|
+
onClick: () => localStorage.setItem('activeTabCDP', t('vehicleProps:title.financing')),
|
|
171
171
|
href: url,
|
|
172
172
|
target,
|
|
173
173
|
rel
|
|
@@ -319,9 +319,8 @@ const VehicleSmallCard: FunctionComponent<IVehicleSmallCardProps> = (props) => {
|
|
|
319
319
|
target,
|
|
320
320
|
rel,
|
|
321
321
|
className: `${styles.redirectClassLink} ${styles.gridAreaTitle}`,
|
|
322
|
-
// ADV-
|
|
323
|
-
|
|
324
|
-
// saved per-car choice / `?mode=` query flag).
|
|
322
|
+
// ADV-116: opening a CDP from a card defaults to the Financing tab.
|
|
323
|
+
onClick: () => localStorage.setItem('activeTabCDP', t('vehicleProps:title.financing')),
|
|
325
324
|
href: url
|
|
326
325
|
})}
|
|
327
326
|
|
|
@@ -374,9 +373,8 @@ const VehicleSmallCard: FunctionComponent<IVehicleSmallCardProps> = (props) => {
|
|
|
374
373
|
target,
|
|
375
374
|
rel,
|
|
376
375
|
className: `${styles.redirectClassLink} ${styles.gridAreaImage}`,
|
|
377
|
-
// ADV-
|
|
378
|
-
|
|
379
|
-
// saved per-car choice / `?mode=` query flag).
|
|
376
|
+
// ADV-116: opening a CDP from a card defaults to the Financing tab.
|
|
377
|
+
onClick: () => localStorage.setItem('activeTabCDP', t('vehicleProps:title.financing')),
|
|
380
378
|
href: url
|
|
381
379
|
})}
|
|
382
380
|
<VehicleInfo {...vehicleInfoProps} />
|
package/data/toAutobahnCar.ts
CHANGED
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
// Every field path below was confirmed against the real code (file:line in
|
|
24
24
|
// ./fieldMapping.ts), not guessed.
|
|
25
25
|
|
|
26
|
-
import { pickDefaultProduct } from '@bytebrand/fe-financing';
|
|
27
|
-
|
|
28
26
|
import { getPriceRating, getPredictablePrice } from '../utils/priceRating';
|
|
29
27
|
import { formatTimestamp } from '../utils/DateUtils';
|
|
30
28
|
import { getPowerLabel } from '../utils/power';
|
|
@@ -429,27 +427,6 @@ export function toAutobahnCar(storeCar: any, deps: ToAutobahnCarDeps = {}): Auto
|
|
|
429
427
|
const leaseMonths = leasingActive ? num(price?.leasing?.paybackPeriod) : undefined;
|
|
430
428
|
const leaseFirstInstallment = leasingActive ? num(price?.leasing?.firstInstallment) : undefined;
|
|
431
429
|
|
|
432
|
-
// --- ADV-181: leading payment product — ONE central rule for every card surface. ---
|
|
433
|
-
// Automatic default = fe-financing's pickDefaultProduct on the same displayed rates the
|
|
434
|
-
// card renders (cheaper valid rate wins, tie → financing, neither valid → 'buy'). The
|
|
435
|
-
// user's saved explicit per-car choice (storeCar.selectedProduct, stamped by fe-main's
|
|
436
|
-
// transformDataForVehicles from FinancingStore) overrides the automatic rule — but only
|
|
437
|
-
// while that product is actually displayable on this card, so a stale "leasing" choice on
|
|
438
|
-
// a car that aged out of leasing eligibility falls back to the automatic rule instead of
|
|
439
|
-
// selecting a product the card can't show. Pure input → pure output: SSR (fe-landing)
|
|
440
|
-
// computes the identical value from the same payload, so hydration never flips the tab.
|
|
441
|
-
const picked = pickDefaultProduct({
|
|
442
|
-
financing: { monthlyInstallment: monthly },
|
|
443
|
-
leasing: { isActive: leasingActive, monthlyInstallment: lease ?? null },
|
|
444
|
-
});
|
|
445
|
-
const savedProduct = (storeCar as any).selectedProduct;
|
|
446
|
-
const defaultMode: 'financing' | 'leasing' | 'buy' =
|
|
447
|
-
savedProduct === 'leasing' && lease != null
|
|
448
|
-
? 'leasing'
|
|
449
|
-
: savedProduct === 'financing' && monthly > 0
|
|
450
|
-
? 'financing'
|
|
451
|
-
: picked.product;
|
|
452
|
-
|
|
453
430
|
// --- optional: list price / savings — ONLY from a real strike price ---
|
|
454
431
|
// transformDataForVehicles exposes oldMonthlyInstallment / highestPrice via
|
|
455
432
|
// the financing spread, and price.historyPriceDifference. There is NO reliable
|
|
@@ -517,7 +494,6 @@ export function toAutobahnCar(storeCar: any, deps: ToAutobahnCarDeps = {}): Auto
|
|
|
517
494
|
|
|
518
495
|
// price
|
|
519
496
|
monthly,
|
|
520
|
-
defaultMode,
|
|
521
497
|
...(finFirstInstallment != null ? { finFirstInstallment } : {}),
|
|
522
498
|
...(finMonths != null ? { finMonths } : {}),
|
|
523
499
|
price: purchase,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebrand/fe-ui-core-autobahn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.135",
|
|
4
4
|
"description": "auto.de md3 (Autobahn) design system — UI primitives, cards, chrome, VDP modules, theme CSS and locales. Ships raw TypeScript source (like fe-ui-core before it); each consumer's bundler compiles it.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"license": "UNLICENSED",
|
package/vdp/VdpModules.tsx
CHANGED
|
@@ -1606,18 +1606,12 @@ export interface VdpStickyBarProps {
|
|
|
1606
1606
|
show: boolean;
|
|
1607
1607
|
/** primary CTA click. */
|
|
1608
1608
|
onSecure?: () => void;
|
|
1609
|
-
/** ADV-181: monthly rate for the CURRENTLY selected payment product (fin/leasing differ) —
|
|
1610
|
-
* falls back to vehicle.monthly (the financing rate) when omitted, the pre-ADV-181 display. */
|
|
1611
|
-
monthly?: number;
|
|
1612
|
-
/** ADV-181: label of the selected product ("Finanzierung"/"Leasing") — replaces the generic
|
|
1613
|
-
* "ab" eyebrow so the sticky bar's label always matches the rate it shows. */
|
|
1614
|
-
productLabel?: string;
|
|
1615
1609
|
/** i18n function (drilled from the page). */
|
|
1616
1610
|
t: TranslationFunction;
|
|
1617
1611
|
}
|
|
1618
1612
|
|
|
1619
1613
|
/** Desktop sticky summary bar (AS24 pattern) — docks to top, driven by `show`. */
|
|
1620
|
-
export const VdpStickyBar: React.FunctionComponent<VdpStickyBarProps> = ({ vehicle, image, show, onSecure,
|
|
1614
|
+
export const VdpStickyBar: React.FunctionComponent<VdpStickyBarProps> = ({ vehicle, image, show, onSecure, t }) => (
|
|
1621
1615
|
<div className={'vdp-stickytop hide-mobile' + (show ? ' vdp-stickytop--on' : '')}>
|
|
1622
1616
|
<div className="container" style={{ display: 'flex', alignItems: 'center', gap: 18, padding: '10px 24px' }}>
|
|
1623
1617
|
<img
|
|
@@ -1643,9 +1637,9 @@ export const VdpStickyBar: React.FunctionComponent<VdpStickyBarProps> = ({ vehic
|
|
|
1643
1637
|
</div>
|
|
1644
1638
|
<div style={{ textAlign: 'right', flex: 'none' }}>
|
|
1645
1639
|
<div style={{ display: 'flex', alignItems: 'baseline', gap: 4, justifyContent: 'flex-end' }}>
|
|
1646
|
-
<span className="md-label-sm">{
|
|
1640
|
+
<span className="md-label-sm">{t('autobahn:sticky.from')}</span>
|
|
1647
1641
|
<span className="num" style={{ fontWeight: 700, fontSize: 20, color: 'var(--md-primary)', letterSpacing: '-.4px' }}>
|
|
1648
|
-
{
|
|
1642
|
+
{vehicle.monthly} €
|
|
1649
1643
|
</span>
|
|
1650
1644
|
<span className="md-label-sm">{t('autobahn:sticky.perMonth')}</span>
|
|
1651
1645
|
</div>
|