@bytebrand/fe-ui-core-autobahn 1.0.97 → 1.0.99

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.
@@ -939,6 +939,8 @@ export const PricePaths: React.FunctionComponent<PricePathsProps> = ({ car, t, c
939
939
  const finFirstInstallment =
940
940
  car.finFirstInstallment != null ? car.finFirstInstallment.toLocaleString('de-DE') : _finFirstInstallment;
941
941
  const finMonths = car.finMonths ?? _finMonths;
942
+ const leasFirstInstallment =
943
+ car.leaseFirstInstallment != null ? car.leaseFirstInstallment.toLocaleString('de-DE') : _leasFirstInstallment;
942
944
  const leasMileage = car.leaseMileage ?? _leasMileage;
943
945
  const leasMonths = car.leaseMonths ?? _leasPeriod;
944
946
  const hasLeasTerms = Boolean(leasMileage && leasMonths);
@@ -979,14 +981,17 @@ export const PricePaths: React.FunctionComponent<PricePathsProps> = ({ car, t, c
979
981
  <PpRow label={t('autobahn:card.price.leasing')} value={car.lease as number} unit="mtl." />
980
982
  {hasLeasTerms && (
981
983
  <div className="pp-sub-terms">
982
- {/* mockup drops the Sonderzahlung figure entirely here (unlike the shared
983
- leaseTerms key mobile/VDP use) and swaps the order to mileage-first —
984
- a dedicated key, not a rework of leaseTerms, so those other callers
985
- keep their own reviewed wording untouched. */}
986
- {t('autobahn:card.price.leaseTermsCompact', {
987
- months: leasMonths,
984
+ {/* dedicated keys (not a rework of leaseTerms) so mobile/VDP's own reviewed
985
+ wording there stays untouched, but includes the same Sonderzahlung figure.
986
+ Split across two lines with an explicit <br/> (column is too narrow for all
987
+ three figures + Details on one line) — forced right after km/Jahr so "36" and
988
+ "Mon." always land on the same line instead of an awkward mid-number wrap. */}
989
+ {t('autobahn:card.price.leaseTermsCompactLine1', {
990
+ firstInstallment: leasFirstInstallment,
988
991
  mileage: leasMileageStr,
989
- })}{' '}
992
+ })}{' · '}
993
+ <br />
994
+ {t('autobahn:card.price.leaseTermsCompactLine2', { months: leasMonths })}{' '}
990
995
  · {detailsLink('leasing')}
991
996
  </div>
992
997
  )}
@@ -12,7 +12,8 @@
12
12
  "financeTerms": "{{firstInstallment}} € Anzahlung · {{months}} Monate",
13
13
  "financeTerms_plural": "{{firstInstallment}} € Anzahlung · {{months}} Monate",
14
14
  "leaseTerms": "{{firstInstallment}} € Sonderzahlung · {{months}} Mon. · {{mileage}} km/Jahr",
15
- "leaseTermsCompact": "{{mileage}} km/Jahr · {{months}} Monate",
15
+ "leaseTermsCompactLine1": "{{firstInstallment}} € Sonderzahlung · {{mileage}} km/Jahr",
16
+ "leaseTermsCompactLine2": "{{months}} Mon.",
16
17
  "detailsLink": "Details",
17
18
  "uvpRateLabel": "UVP-Rate",
18
19
  "uvpRateTooltipBody": "Rechnerische Vergleichsrate auf Basis der unverbindlichen Preisempfehlung des Herstellers und mit denselben Finanzierungsparametern wie das Angebot. Keine früher verlangte Rate. Das Rundum-Sorglos-Paket wird einmalig separat berechnet.",
@@ -12,7 +12,8 @@
12
12
  "financeTerms": "€{{firstInstallment}} down payment · {{months}} months",
13
13
  "financeTerms_plural": "€{{firstInstallment}} down payment · {{months}} months term",
14
14
  "leaseTerms": "€{{firstInstallment}} down payment · {{months}} mo. · {{mileage}} km/year",
15
- "leaseTermsCompact": "{{mileage}} km/year · {{months}} months",
15
+ "leaseTermsCompactLine1": "€{{firstInstallment}} down payment · {{mileage}} km/year",
16
+ "leaseTermsCompactLine2": "{{months}} mo.",
16
17
  "detailsLink": "Details",
17
18
  "uvpRateLabel": "UVP rate",
18
19
  "uvpRateTooltipBody": "Calculated comparison rate based on the manufacturer's non-binding price recommendation, using the same financing parameters as the offer. Not a previously requested rate. The all-inclusive package is billed separately, as a one-off.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/fe-ui-core-autobahn",
3
- "version": "1.0.97",
3
+ "version": "1.0.99",
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/theme/md3.css CHANGED
@@ -5844,9 +5844,10 @@ line-height: 31px;
5844
5844
  .md3 .vdp-bottom-bar {
5845
5845
  position: fixed;
5846
5846
  left: 0;
5847
+ right: 0;
5847
5848
  bottom: 0;
5848
5849
  z-index: 60;
5849
- width: 390px;
5850
+ width: auto;
5850
5851
  height: 196px;
5851
5852
  background: rgba(244, 243, 243, 0.95);
5852
5853
  border: 1px solid #D4DDE7;
@@ -8637,7 +8638,9 @@ color: #005CFF;
8637
8638
  font-size: 13px;
8638
8639
  line-height: 15px;
8639
8640
  color: #111820;
8641
+ margin: 0px 0px;
8640
8642
  margin-bottom: 12px;
8643
+ vertical-align: -3px;
8641
8644
  }
8642
8645
  /* "Finanzierungsdetails"/"Leasing-Details" reads as a link here (unlike CarCard's quiet
8643
8646
  .cc-terms-link, which stays text-colored on purpose) — underlined. */
@@ -8657,11 +8660,11 @@ color: #005CFF;
8657
8660
  font-weight: 700 !important;
8658
8661
  color: var(--md-on-surface-variant) !important;
8659
8662
  }
8660
- /* figma pricing-card padding is 16 (inline says 20 — hence !important); the side-by-side
8663
+ /* figma pricing-card padding is 15px 12px (inline says 20 — hence !important); the side-by-side
8661
8664
  CTAs must be allowed to SHRINK (mbtn is nowrap min-width:auto, 0-30px padding — the pair
8662
8665
  alone mins out wider than the phone card) */
8663
8666
  .md3 .vdp-aside > .mcard {
8664
- padding: 16px !important;
8667
+ padding: 15px 12px !important;
8665
8668
  }
8666
8669
  .md3 .fin-cta-row .mbtn {
8667
8670
  min-width: 0;
@@ -19,6 +19,13 @@ export function formatPct(n: number): string {
19
19
  return `${n.toFixed(2).replace('.', ',')} %`;
20
20
  }
21
21
 
22
+ /** Monetary figure → de-DE grouped string with fixed cents (e.g. 44333 → "44.333,00",
23
+ * 42243.9 → "42.243,90"). Unlike formatEur, always shows exactly 2 decimals — for the "Repräsentatives
24
+ * Beispiel" breakdown table (FinanceDetailsModal), where every € line is expected to carry cents. */
25
+ export function formatEurCents(n: number): string {
26
+ return n.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
27
+ }
28
+
22
29
  export interface FinanceExampleFields {
23
30
  price: number;
24
31
  apr: number;
@@ -28,7 +28,7 @@ import { Button, Dropdown, DropdownOption, Icon, Spec, StatChip, Stars } from '.
28
28
  import { CO2_CLASSES, CO2_COLORS, TIER_LABELS, TIER_KEYS, TIER_COLORS, TIER_BACKGROUNDS } from '../constants';
29
29
  import { defaultVdpSpecs, EquipmentGroups, PriceRatingBands, VehicleDetail, VdpSpec, VdpReview } from './types';
30
30
  import { AddServicesTooltipBody, CalcRow, DocCheckIcon, EvalBar, expanderBtnStyle, FinanceMode, Slider, TermChips, ToggleRow } from './FinanceCalculator';
31
- import { formatEur as eur, formatPct as pct } from '../utils/financeFormat';
31
+ import { formatEur as eur, formatEurCents as eurCents, formatPct as pct } from '../utils/financeFormat';
32
32
 
33
33
  /** Figma "check with open arc" glyph (modern lucide circle-check-big; the bundled lucide
34
34
  * 0.288 only ships the closed-circle variant, so the two paths are inlined). */
@@ -2082,51 +2082,51 @@ export const FinanceDetailsModal: React.FunctionComponent<FinanceDetailsModalPro
2082
2082
  const subtotalWithPackage = ratesSum != null ? ratesSum + down + (hasAddServicesRow ? addServicesRowValue : 0) : undefined;
2083
2083
  const grandTotal = subtotalWithPackage != null ? subtotalWithPackage + residual : undefined;
2084
2084
  rows = [
2085
- [t('autobahn:modal.leaseVehiclePrice'), `${eur(price)} €`],
2085
+ [t('autobahn:modal.leaseVehiclePrice'), `${eurCents(price)} €`],
2086
2086
  [t('autobahn:modal.term'), t('autobahn:modal.months', { months: term, count: term })],
2087
2087
  ...(annualMileage != null ? ([[t('autobahn:modal.annualMileage'), `${eur(annualMileage)} km`]] as Array<[string, string]>) : []),
2088
- [t('autobahn:modal.leaseDownPayment'), `${eur(down)} €`],
2089
- [t('autobahn:modal.leasingRateCount', { count: term }), `${eur(monthly)} €`],
2090
- [t('autobahn:modal.finalPaymentDue'), `${eur(0)} €`],
2091
- ...(residual > 0 ? ([[t('autobahn:modal.residualValue'), `${eur(residual)} €`]] as Array<[string, string]>) : []),
2088
+ [t('autobahn:modal.leaseDownPayment'), `${eurCents(down)} €`],
2089
+ [t('autobahn:modal.leasingRateCount', { count: term }), `${eurCents(monthly)} €`],
2090
+ [t('autobahn:modal.finalPaymentDue'), `${eurCents(0)} €`],
2091
+ ...(residual > 0 ? ([[t('autobahn:modal.residualValue'), `${eurCents(residual)} €`]] as Array<[string, string]>) : []),
2092
2092
  ...(ratesSum != null
2093
- ? ([[t('autobahn:modal.rateSumLabel', { term, amount: eur(monthly) }), `${eur(ratesSum)} €`, true]] as Array<[string, string, boolean]>)
2093
+ ? ([[t('autobahn:modal.rateSumLabel', { term, amount: eurCents(monthly) }), `${eurCents(ratesSum)} €`, true]] as Array<[string, string, boolean]>)
2094
2094
  : []),
2095
- ...(ratesSum != null ? ([[t('autobahn:modal.leaseDownPayment'), `${eur(down)} €`]] as Array<[string, string]>) : []),
2095
+ ...(ratesSum != null ? ([[t('autobahn:modal.leaseDownPayment'), `${eurCents(down)} €`]] as Array<[string, string]>) : []),
2096
2096
  ...(ratesSum != null && hasAddServicesRow
2097
- ? ([[t('autobahn:modal.addServicesRowLease'), `${eur(addServicesRowValue)} €`]] as Array<[string, string]>)
2097
+ ? ([[t('autobahn:modal.addServicesRowLease'), `${eurCents(addServicesRowValue)} €`]] as Array<[string, string]>)
2098
2098
  : []),
2099
2099
  ...(subtotalWithPackage != null
2100
- ? ([[hasAddServicesRow ? t('autobahn:modal.subtotalWithPackage') : t('autobahn:modal.subtotalNoPackage'), `${eur(subtotalWithPackage)} €`, true]] as Array<
2100
+ ? ([[hasAddServicesRow ? t('autobahn:modal.subtotalWithPackage') : t('autobahn:modal.subtotalNoPackage'), `${eurCents(subtotalWithPackage)} €`, true]] as Array<
2101
2101
  [string, string, boolean]
2102
2102
  >)
2103
2103
  : []),
2104
- ...(residual > 0 && grandTotal != null ? ([[t('autobahn:modal.residualValue'), `${eur(residual)} €`]] as Array<[string, string]>) : []),
2104
+ ...(residual > 0 && grandTotal != null ? ([[t('autobahn:modal.residualValue'), `${eurCents(residual)} €`]] as Array<[string, string]>) : []),
2105
2105
  ...(grandTotal != null
2106
- ? ([[t('autobahn:modal.grandTotalWithResidual'), `${eur(grandTotal)} €`, true]] as Array<[string, string, boolean]>)
2106
+ ? ([[t('autobahn:modal.grandTotalWithResidual'), `${eurCents(grandTotal)} €`, true]] as Array<[string, string, boolean]>)
2107
2107
  : []),
2108
- ...(listPrice != null && listPrice > 0 ? ([[t('autobahn:modal.listPriceLease'), `${eur(listPrice)} €`]] as Array<[string, string]>) : []),
2108
+ ...(listPrice != null && listPrice > 0 ? ([[t('autobahn:modal.listPriceLease'), `${eurCents(listPrice)} €`]] as Array<[string, string]>) : []),
2109
2109
  ];
2110
2110
  } else {
2111
2111
  rows = [
2112
- [t('autobahn:modal.vehiclePrice'), `${eur(price)} €`],
2112
+ [t('autobahn:modal.vehiclePrice'), `${eurCents(price)} €`],
2113
2113
  [t('autobahn:modal.term'), t('autobahn:modal.months', { months: term, count: term })],
2114
- [t('autobahn:modal.downPayment'), `${eur(down)} €`],
2115
- [t('autobahn:modal.monthlyRateCount', { count: term }), `${eur(monthly)} €`],
2116
- ...(finalInstallment != null && finalInstallment > 0 ? ([[t('autobahn:modal.finalInstallment'), `${eur(finalInstallment)} €`]] as Array<[string, string]>) : []),
2114
+ [t('autobahn:modal.downPayment'), `${eurCents(down)} €`],
2115
+ [t('autobahn:modal.monthlyRateCount', { count: term }), `${eurCents(monthly)} €`],
2116
+ ...(finalInstallment != null && finalInstallment > 0 ? ([[t('autobahn:modal.finalInstallment'), `${eurCents(finalInstallment)} €`]] as Array<[string, string]>) : []),
2117
2117
  ...(hasAddServicesRow
2118
- ? ([[t('autobahn:modal.addServicesRow'), `${eur(addServicesRowValue)} €`]] as Array<[string, string]>)
2118
+ ? ([[t('autobahn:modal.addServicesRow'), `${eurCents(addServicesRowValue)} €`]] as Array<[string, string]>)
2119
2119
  : []),
2120
2120
  ...(nominalRate != null && nominalRate > 0 ? ([[t('autobahn:modal.nominalRate'), pct(nominalRate)]] as Array<[string, string]>) : []),
2121
2121
  [t('autobahn:modal.effectiveRate'), pct(apr)],
2122
- [t('autobahn:modal.netLoanAmount'), `${eur(netto)} €`],
2123
- ...(grossAmount != null && grossAmount > 0 ? ([[t('autobahn:modal.totalRepayment'), `${eur(grossAmount)} €`]] as Array<[string, string]>) : []),
2122
+ [t('autobahn:modal.netLoanAmount'), `${eurCents(netto)} €`],
2123
+ ...(grossAmount != null && grossAmount > 0 ? ([[t('autobahn:modal.totalRepayment'), `${eurCents(grossAmount)} €`]] as Array<[string, string]>) : []),
2124
2124
  ...(totalCost != null
2125
- ? ([[hasAddServices ? t('autobahn:modal.totalCostWithPackage') : t('autobahn:modal.totalCost'), `${eur(totalCost)} €`, true]] as Array<
2125
+ ? ([[hasAddServices ? t('autobahn:modal.totalCostWithPackage') : t('autobahn:modal.totalCost'), `${eurCents(totalCost)} €`, true]] as Array<
2126
2126
  [string, string, boolean]
2127
2127
  >)
2128
2128
  : []),
2129
- ...(listPrice != null && listPrice > 0 ? ([[t('autobahn:modal.listPrice'), `${eur(listPrice)} €`]] as Array<[string, string]>) : []),
2129
+ ...(listPrice != null && listPrice > 0 ? ([[t('autobahn:modal.listPrice'), `${eurCents(listPrice)} €`]] as Array<[string, string]>) : []),
2130
2130
  ];
2131
2131
  }
2132
2132
  const breakdownRows = rows.map(([l, v, bold], i) => (