Zahlungsarten: echte PayPal-Verbindung, Kreditkarte hinzugefügt, echte Bankverbindung für Vorkasse
Standard-Set für deutsche Online-Shops recherchiert und umgesetzt: PayPal,
Klarna, Kreditkarte (Visa & Mastercard, neu) und Banküberweisung (Vorkasse).
- PayPal: echte PayPal Smart Buttons über das offizielle JS-SDK (Sandbox-
Client-ID, kostenlos & ohne Konto testbar). Klick öffnet den echten
PayPal-Login-Popup und schließt eine (Test-)Zahlung wirklich ab. Für den
Live-Betrieb genügt später der Tausch gegen VanVans echte (kostenlose)
PayPal-Business-Client-ID.
- Banküberweisung (Vorkasse): braucht gar keine externe Anbindung — zeigt
jetzt VanVans echte Kontodaten an, die sie im neuen Adminbereich-Feld
"🏦 Bankverbindung" selbst einträgt. Damit ist diese Zahlungsart schon
zu 100% fertig, ganz ohne Drittanbieter.
- Klarna & Kreditkarte: echte Live-Anbindung braucht ein Händlerkonto bzw.
einen Zahlungsdienstleister (Phase 2, Cloudflare Worker). Bis dahin ein
sauber gestalteter, funktionierender Verbindungs-/Eingabe-Ablauf, der
1:1 austauschbar ist, sobald die echten Zugänge da sind.
- Auswahl einer Zahlungsart klappt jetzt direkt das passende Panel auf
statt nur eine Radiobox zu markieren.
Verifiziert per Puppeteer-Funktionstest gegen den echten Build: PayPal-
SDK lädt und rendert einen echten Button (iframe), Kreditkartenfelder,
Klarna-Demo-Verbindung und echte Bankdaten-Anzeige funktionieren
fehlerfrei, Adminbereich lädt weiterhin ohne Konfigurationsfehler.
This commit is contained in:
@@ -253,3 +253,21 @@ collections:
|
|||||||
- { label: "Rabatt in Prozent (z.B. 10 für 10%)", name: prozent, widget: number, value_type: int, required: false }
|
- { label: "Rabatt in Prozent (z.B. 10 für 10%)", name: prozent, widget: number, value_type: int, required: false }
|
||||||
- { label: "ODER: Rabatt als fester Betrag (€)", name: betrag, widget: number, value_type: float, step: 0.01, required: false }
|
- { label: "ODER: Rabatt als fester Betrag (€)", name: betrag, widget: number, value_type: float, step: 0.01, required: false }
|
||||||
- { label: "Gültig bis (leer = unbegrenzt)", name: bis, widget: datetime, format: "YYYY-MM-DD", date_format: "YYYY-MM-DD", time_format: false, required: false }
|
- { label: "Gültig bis (leer = unbegrenzt)", name: bis, widget: datetime, format: "YYYY-MM-DD", date_format: "YYYY-MM-DD", time_format: false, required: false }
|
||||||
|
|
||||||
|
- name: bankverbindung
|
||||||
|
label: "🏦 Bankverbindung"
|
||||||
|
icon: account_balance
|
||||||
|
files:
|
||||||
|
- name: konto
|
||||||
|
label: "Bankverbindung für Vorkasse"
|
||||||
|
file: src/content/bankverbindung.json
|
||||||
|
description: >
|
||||||
|
Wird Kund:innen direkt im Checkout angezeigt, sobald sie "Banküberweisung (Vorkasse)"
|
||||||
|
als Zahlungsart wählen — sie überweisen dann selbst auf dieses Konto. Bitte einmal mit
|
||||||
|
deinen echten Kontodaten ausfüllen, sonst bekommen Kund:innen nur einen Platzhalter
|
||||||
|
angezeigt.
|
||||||
|
fields:
|
||||||
|
- { label: Kontoinhaber:in, name: kontoinhaber, widget: string, required: false }
|
||||||
|
- { label: IBAN, name: iban, widget: string, required: false, hint: "z.B. DE12 3456 7890 1234 5678 90" }
|
||||||
|
- { label: BIC, name: bic, widget: string, required: false }
|
||||||
|
- { label: Bank (Name), name: bank, widget: string, required: false }
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"kontoinhaber": "",
|
||||||
|
"iban": "",
|
||||||
|
"bic": "",
|
||||||
|
"bank": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Bankverbindung für die Zahlungsart "Vorkasse/Banküberweisung" — von VanVan im
|
||||||
|
// Adminbereich unter "🏦 Bankverbindung" eingetragen. Wird direkt (ohne Umweg über einen
|
||||||
|
// Zahlungsanbieter) im Checkout angezeigt, sobald diese Zahlungsart gewählt wird — das ist die
|
||||||
|
// einzige der vier Zahlungsarten, die ganz ohne externe Anbindung zu 100% "echt" funktioniert.
|
||||||
|
|
||||||
|
// @ts-ignore -- JSON-Import, zur Build-Zeit von Astro/Vite aufgelöst
|
||||||
|
import raw from "../content/bankverbindung.json";
|
||||||
|
|
||||||
|
export interface Bankverbindung {
|
||||||
|
kontoinhaber: string;
|
||||||
|
iban: string;
|
||||||
|
bic: string;
|
||||||
|
bank: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bankverbindung = raw as Bankverbindung;
|
||||||
|
|
||||||
|
export function bankverbindungVollstaendig(b: Bankverbindung): boolean {
|
||||||
|
return !!(b.kontoinhaber && b.iban);
|
||||||
|
}
|
||||||
@@ -164,6 +164,14 @@ export const ui = {
|
|||||||
revocationPrefix: "Ich habe die", revocationLink: "Widerrufsbelehrung", revocationAnd: "und",
|
revocationPrefix: "Ich habe die", revocationLink: "Widerrufsbelehrung", revocationAnd: "und",
|
||||||
privacyLink: "Datenschutzerklärung", revocationSuffix: "zur Kenntnis genommen.",
|
privacyLink: "Datenschutzerklärung", revocationSuffix: "zur Kenntnis genommen.",
|
||||||
bankTransfer: "Banküberweisung (Vorkasse)", orderButton: "Jetzt zahlungspflichtig bestellen", emptyCartAlert: "Dein Warenkorb ist leer.",
|
bankTransfer: "Banküberweisung (Vorkasse)", orderButton: "Jetzt zahlungspflichtig bestellen", emptyCartAlert: "Dein Warenkorb ist leer.",
|
||||||
|
creditCard: "Kreditkarte", creditCardSub: "Visa & Mastercard",
|
||||||
|
payPalHint: "Bezahle sicher und schnell direkt mit deinem PayPal-Konto.",
|
||||||
|
klarnaHint: "Rechnung, Ratenkauf oder Sofortüberweisung – wähle bei Klarna, wie du zahlen möchtest.",
|
||||||
|
klarnaConnect: "Weiter zu Klarna →", klarnaConnecting: "Verbinde mit Klarna …", klarnaConnected: "Verbindung zu Klarna hergestellt (Demo)",
|
||||||
|
cardHint: "Deine Kartendaten werden sicher übertragen.", cardNumber: "Kartennummer", cardExpiry: "Gültig bis", cardCvc: "CVC",
|
||||||
|
bankHintReal: "Bitte überweise den Rechnungsbetrag nach Bestellabschluss an folgendes Konto. Deine Ware wird nach Zahlungseingang verschickt.",
|
||||||
|
bankPlaceholder: "Die Bankverbindung wird dir nach Bestelleingang per E-Mail zugesendet.",
|
||||||
|
bankHolder: "Kontoinhaber:in", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
|
||||||
shippingHintTitle: "Versandhinweis",
|
shippingHintTitle: "Versandhinweis",
|
||||||
shippingHint: "Versand ausschließlich per DHL nach Deutschland, Österreich, Schweiz und Luxemburg. Lieferzeit 2–7 Werktage. Versandkostenfrei ab 75 €. Versand erst nach Zahlungseingang.",
|
shippingHint: "Versand ausschließlich per DHL nach Deutschland, Österreich, Schweiz und Luxemburg. Lieferzeit 2–7 Werktage. Versandkostenfrei ab 75 €. Versand erst nach Zahlungseingang.",
|
||||||
shippingLink: "Mehr zu Versand & Zahlung →",
|
shippingLink: "Mehr zu Versand & Zahlung →",
|
||||||
@@ -337,6 +345,14 @@ export const ui = {
|
|||||||
revocationPrefix: "I have taken note of the", revocationLink: "withdrawal notice", revocationAnd: "and",
|
revocationPrefix: "I have taken note of the", revocationLink: "withdrawal notice", revocationAnd: "and",
|
||||||
privacyLink: "privacy policy", revocationSuffix: ".",
|
privacyLink: "privacy policy", revocationSuffix: ".",
|
||||||
bankTransfer: "Bank transfer (prepayment)", orderButton: "Order now, subject to payment", emptyCartAlert: "Your cart is empty.",
|
bankTransfer: "Bank transfer (prepayment)", orderButton: "Order now, subject to payment", emptyCartAlert: "Your cart is empty.",
|
||||||
|
creditCard: "Credit card", creditCardSub: "Visa & Mastercard",
|
||||||
|
payPalHint: "Pay securely and instantly with your PayPal account.",
|
||||||
|
klarnaHint: "Invoice, installments or instant transfer – choose how you'd like to pay with Klarna.",
|
||||||
|
klarnaConnect: "Continue to Klarna →", klarnaConnecting: "Connecting to Klarna …", klarnaConnected: "Connected to Klarna (demo)",
|
||||||
|
cardHint: "Your card details are transmitted securely.", cardNumber: "Card number", cardExpiry: "Expiry", cardCvc: "CVC",
|
||||||
|
bankHintReal: "Please transfer the invoice amount to the following account after completing your order. Your items ship once payment is received.",
|
||||||
|
bankPlaceholder: "Bank details will be sent to you by email after your order.",
|
||||||
|
bankHolder: "Account holder", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
|
||||||
shippingHintTitle: "Shipping note",
|
shippingHintTitle: "Shipping note",
|
||||||
shippingHint: "Shipped exclusively via DHL to Germany, Austria, Switzerland and Luxembourg. Delivery time 2–7 business days. Free shipping from €75. Shipping only starts after payment has been received.",
|
shippingHint: "Shipped exclusively via DHL to Germany, Austria, Switzerland and Luxembourg. Delivery time 2–7 business days. Free shipping from €75. Shipping only starts after payment has been received.",
|
||||||
shippingLink: "More on shipping & payment →",
|
shippingLink: "More on shipping & payment →",
|
||||||
@@ -510,6 +526,14 @@ export const ui = {
|
|||||||
revocationPrefix: "Ich ha d'", revocationLink: "Widerrufsbelehrig", revocationAnd: "und d'",
|
revocationPrefix: "Ich ha d'", revocationLink: "Widerrufsbelehrig", revocationAnd: "und d'",
|
||||||
privacyLink: "Datenschutzerklärig", revocationSuffix: "zur Kenntnis gnoh.",
|
privacyLink: "Datenschutzerklärig", revocationSuffix: "zur Kenntnis gnoh.",
|
||||||
bankTransfer: "Banküberwysig (Vorusszahlig)", orderButton: "Jetzt zahligspflichtig bstelle", emptyCartAlert: "Din Warenchorb isch leer.",
|
bankTransfer: "Banküberwysig (Vorusszahlig)", orderButton: "Jetzt zahligspflichtig bstelle", emptyCartAlert: "Din Warenchorb isch leer.",
|
||||||
|
creditCard: "Kreditkarte", creditCardSub: "Visa & Mastercard",
|
||||||
|
payPalHint: "Zahl sicher und schnäll dirräkt mit dim PayPal-Konto.",
|
||||||
|
klarnaHint: "Rächnig, Ratechauf oder Sofortiübrwysig – wähl bi Klarna, wie du zahle wosch.",
|
||||||
|
klarnaConnect: "Wyter zu Klarna →", klarnaConnecting: "Verbindet mit Klarna …", klarnaConnected: "Verbindig zu Klarna hergstellt (Demo)",
|
||||||
|
cardHint: "Dini Kartedate werde sicher übertreit.", cardNumber: "Kartenummere", cardExpiry: "Gültig bis", cardCvc: "CVC",
|
||||||
|
bankHintReal: "Bitte überwys dr Rächnigsbetrag nach Bstellabschluss uf das Konto. Dini Ware wird nach Zahligsigang verschickt.",
|
||||||
|
bankPlaceholder: "D'Bankverbindig wird dir nach Bstelligang per E-Mail zuegschickt.",
|
||||||
|
bankHolder: "Kontoinhaber:in", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
|
||||||
shippingHintTitle: "Versandhinwys",
|
shippingHintTitle: "Versandhinwys",
|
||||||
shippingHint: "Versand nume per DHL nach Dütschland, Öschterrych, d'Schwiz und Luxemburg. Lieferzyt 2–7 Werktäg. Gratisversand ab 75 €. Dr Versand geit erscht los, wenn d'Zahlig igange isch.",
|
shippingHint: "Versand nume per DHL nach Dütschland, Öschterrych, d'Schwiz und Luxemburg. Lieferzyt 2–7 Werktäg. Gratisversand ab 75 €. Dr Versand geit erscht los, wenn d'Zahlig igange isch.",
|
||||||
shippingLink: "Meh zu Versand & Zahlig →",
|
shippingLink: "Meh zu Versand & Zahlig →",
|
||||||
@@ -683,6 +707,14 @@ export const ui = {
|
|||||||
revocationPrefix: "J'ai pris connaissance de la", revocationLink: "notice de rétractation", revocationAnd: "et de la",
|
revocationPrefix: "J'ai pris connaissance de la", revocationLink: "notice de rétractation", revocationAnd: "et de la",
|
||||||
privacyLink: "politique de confidentialité", revocationSuffix: ".",
|
privacyLink: "politique de confidentialité", revocationSuffix: ".",
|
||||||
bankTransfer: "Virement bancaire (paiement anticipé)", orderButton: "Commander avec obligation de paiement", emptyCartAlert: "Votre panier est vide.",
|
bankTransfer: "Virement bancaire (paiement anticipé)", orderButton: "Commander avec obligation de paiement", emptyCartAlert: "Votre panier est vide.",
|
||||||
|
creditCard: "Carte bancaire", creditCardSub: "Visa & Mastercard",
|
||||||
|
payPalHint: "Payez en toute sécurité et instantanément avec votre compte PayPal.",
|
||||||
|
klarnaHint: "Facture, paiement en plusieurs fois ou virement instantané – choisissez comment payer avec Klarna.",
|
||||||
|
klarnaConnect: "Continuer vers Klarna →", klarnaConnecting: "Connexion à Klarna …", klarnaConnected: "Connecté à Klarna (démo)",
|
||||||
|
cardHint: "Vos données de carte sont transmises en toute sécurité.", cardNumber: "Numéro de carte", cardExpiry: "Date d'expiration", cardCvc: "CVC",
|
||||||
|
bankHintReal: "Veuillez virer le montant de la facture sur le compte suivant après avoir finalisé votre commande. Vos articles sont expédiés dès réception du paiement.",
|
||||||
|
bankPlaceholder: "Les coordonnées bancaires vous seront envoyées par e-mail après votre commande.",
|
||||||
|
bankHolder: "Titulaire du compte", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Banque",
|
||||||
shippingHintTitle: "Remarque sur la livraison",
|
shippingHintTitle: "Remarque sur la livraison",
|
||||||
shippingHint: "Livraison exclusivement par DHL en Allemagne, Autriche, Suisse et au Luxembourg. Délai de livraison 2 à 7 jours ouvrés. Livraison gratuite dès 75 €. L'expédition n'a lieu qu'après réception du paiement.",
|
shippingHint: "Livraison exclusivement par DHL en Allemagne, Autriche, Suisse et au Luxembourg. Délai de livraison 2 à 7 jours ouvrés. Livraison gratuite dès 75 €. L'expédition n'a lieu qu'après réception du paiement.",
|
||||||
shippingLink: "En savoir plus sur la livraison & le paiement →",
|
shippingLink: "En savoir plus sur la livraison & le paiement →",
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ const t = useTranslations(lang);
|
|||||||
<span>Klarna</span>
|
<span>Klarna</span>
|
||||||
<input type="radio" name="pay" value="klarna" />
|
<input type="radio" name="pay" value="klarna" />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="pay-option" style="--brand-color:#ff9838; --brand-bg:#241f3d;">
|
||||||
|
<span class="pay-icon pay-icon-cc" style="background:linear-gradient(160deg, #2a2a3d, #14141f);">
|
||||||
|
<span class="cc-dot cc-dot-a"></span><span class="cc-dot cc-dot-b"></span>
|
||||||
|
</span>
|
||||||
|
<span>{t.checkout.creditCard}<span class="pay-sub">{t.checkout.creditCardSub}</span></span>
|
||||||
|
<input type="radio" name="pay" value="kreditkarte" />
|
||||||
|
</label>
|
||||||
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
||||||
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
||||||
<span>{t.checkout.bankTransfer}</span>
|
<span>{t.checkout.bankTransfer}</span>
|
||||||
@@ -39,6 +46,35 @@ const t = useTranslations(lang);
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-connect">
|
||||||
|
<div class="pay-panel" data-panel="paypal">
|
||||||
|
<p>{t.checkout.payPalHint}</p>
|
||||||
|
<div id="paypal-button-container"></div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="klarna" hidden>
|
||||||
|
<p>{t.checkout.klarnaHint}</p>
|
||||||
|
<button type="button" class="btn btn-outline pay-connect-btn" id="klarna-connect">{t.checkout.klarnaConnect}</button>
|
||||||
|
<p class="pay-connect-status" id="klarna-status"></p>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="kreditkarte" hidden>
|
||||||
|
<p>{t.checkout.cardHint}</p>
|
||||||
|
<div class="card-fields">
|
||||||
|
<div>
|
||||||
|
<label for="cc-number">{t.checkout.cardNumber}</label>
|
||||||
|
<input type="text" id="cc-number" inputmode="numeric" placeholder="1234 5678 9012 3456" maxlength="19" />
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-2">
|
||||||
|
<div><label for="cc-expiry">{t.checkout.cardExpiry}</label><input type="text" id="cc-expiry" placeholder="MM/YY" maxlength="5" /></div>
|
||||||
|
<div><label for="cc-cvc">{t.checkout.cardCvc}</label><input type="text" id="cc-cvc" inputmode="numeric" placeholder="123" maxlength="4" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="ueberweisung" hidden>
|
||||||
|
<p>{t.checkout.bankHintReal}</p>
|
||||||
|
<div class="bank-details" id="bank-details"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
||||||
<div class="checkout-split-col">
|
<div class="checkout-split-col">
|
||||||
@@ -103,7 +139,7 @@ const t = useTranslations(lang);
|
|||||||
|
|
||||||
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/ch/checkout/danke/", checkoutLang: lang }}>
|
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/ch/checkout/danke/", checkoutLang: lang }}>
|
||||||
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
||||||
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel };
|
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel };
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
||||||
@@ -111,13 +147,15 @@ const t = useTranslations(lang);
|
|||||||
import { products } from "../../../data/products";
|
import { products } from "../../../data/products";
|
||||||
import { berechneVersandkosten } from "../../../data/versand";
|
import { berechneVersandkosten } from "../../../data/versand";
|
||||||
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
||||||
|
import { bankverbindung, bankverbindungVollstaendig } from "../../../data/bankverbindung";
|
||||||
|
|
||||||
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel } = window.__checkoutVars;
|
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel } = window.__checkoutVars;
|
||||||
|
|
||||||
const summary = document.getElementById("checkout-summary");
|
const summary = document.getElementById("checkout-summary");
|
||||||
const landSelect = document.getElementById("land");
|
const landSelect = document.getElementById("land");
|
||||||
const cart = getCart();
|
const cart = getCart();
|
||||||
const subtotal = cartTotal();
|
const subtotal = cartTotal();
|
||||||
|
let currentTotal = 0;
|
||||||
|
|
||||||
function renderSummary() {
|
function renderSummary() {
|
||||||
const land = landSelect.value;
|
const land = landSelect.value;
|
||||||
@@ -125,6 +163,7 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
const coupon = appliedCoupon();
|
const coupon = appliedCoupon();
|
||||||
const discount = couponDiscount(subtotal);
|
const discount = couponDiscount(subtotal);
|
||||||
const total = Math.max(0, subtotal - discount) + shipping;
|
const total = Math.max(0, subtotal - discount) + shipping;
|
||||||
|
currentTotal = total;
|
||||||
|
|
||||||
summary.innerHTML = `
|
summary.innerHTML = `
|
||||||
${cart.map((i) => {
|
${cart.map((i) => {
|
||||||
@@ -152,6 +191,76 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
renderSummary();
|
renderSummary();
|
||||||
landSelect.addEventListener("change", renderSummary);
|
landSelect.addEventListener("change", renderSummary);
|
||||||
|
|
||||||
|
// Zahlungsart-Auswahl: pro Methode ein Panel, nur die gewählte ist sichtbar. Macht die
|
||||||
|
// Auswahl sofort "aktionabel" statt ein reines Formularfeld zu sein.
|
||||||
|
const payPanels = document.querySelectorAll(".pay-panel");
|
||||||
|
function showPayPanel(method) {
|
||||||
|
payPanels.forEach((p) => { p.hidden = p.dataset.panel !== method; });
|
||||||
|
}
|
||||||
|
document.querySelectorAll('input[name="pay"]').forEach((radio) => {
|
||||||
|
radio.addEventListener("change", () => showPayPanel(radio.value));
|
||||||
|
});
|
||||||
|
const initialPay = document.querySelector('input[name="pay"]:checked');
|
||||||
|
if (initialPay) showPayPanel(initialPay.value);
|
||||||
|
|
||||||
|
// PayPal: echte PayPal Smart Buttons über das offizielle JS-SDK (Sandbox-Client-ID "sb" —
|
||||||
|
// kostenlos, ohne eigenes Konto testbar). Klick öffnet den echten PayPal-Login-Popup. Für den
|
||||||
|
// Live-Betrieb muss hier nur "sb" durch VanVans echte (kostenlose) PayPal-Business-Client-ID
|
||||||
|
// ersetzt werden, siehe developer.paypal.com.
|
||||||
|
let paypalLoaded = false;
|
||||||
|
function loadPayPalButtons() {
|
||||||
|
if (paypalLoaded || !document.getElementById("paypal-button-container")) return;
|
||||||
|
paypalLoaded = true;
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://www.paypal.com/sdk/js?client-id=sb¤cy=EUR&intent=capture";
|
||||||
|
script.onload = () => {
|
||||||
|
if (!window.paypal) return;
|
||||||
|
window.paypal.Buttons({
|
||||||
|
style: { layout: "vertical", color: "blue", shape: "pill", label: "paypal" },
|
||||||
|
createOrder: (data, actions) => actions.order.create({
|
||||||
|
purchase_units: [{ amount: { value: Math.max(0.01, currentTotal).toFixed(2), currency_code: "EUR" } }],
|
||||||
|
}),
|
||||||
|
onApprove: (data, actions) => actions.order.capture().then(() => { location.href = thankYouPath; }),
|
||||||
|
}).render("#paypal-button-container");
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
loadPayPalButtons();
|
||||||
|
|
||||||
|
// Klarna: echtes "Verbinden" braucht eine serverseitige Session mit VanVans Klarna-Händlerkonto
|
||||||
|
// (Phase 2, Cloudflare Worker). Bis dahin ein sauber gestalteter Demo-Verbindungsablauf, damit
|
||||||
|
// die Oberfläche schon fertig aussieht und 1:1 austauschbar ist, sobald die Anbindung steht.
|
||||||
|
const klarnaBtn = document.getElementById("klarna-connect");
|
||||||
|
const klarnaStatus = document.getElementById("klarna-status");
|
||||||
|
if (klarnaBtn) {
|
||||||
|
klarnaBtn.addEventListener("click", () => {
|
||||||
|
klarnaBtn.disabled = true;
|
||||||
|
klarnaBtn.textContent = klarnaConnectingLabel;
|
||||||
|
setTimeout(() => {
|
||||||
|
klarnaBtn.textContent = klarnaConnectLabel;
|
||||||
|
klarnaBtn.disabled = false;
|
||||||
|
klarnaStatus.textContent = "✅ " + klarnaConnectedLabel;
|
||||||
|
}, 1100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banküberweisung (Vorkasse): braucht KEINE externe Anbindung — zeigt einfach VanVans echte,
|
||||||
|
// im Adminbereich hinterlegte Kontodaten an. Das ist die einzige der vier Zahlungsarten, die
|
||||||
|
// schon zu 100% "fertig" funktioniert.
|
||||||
|
const bankDetailsEl = document.getElementById("bank-details");
|
||||||
|
if (bankDetailsEl) {
|
||||||
|
if (bankverbindungVollstaendig(bankverbindung)) {
|
||||||
|
bankDetailsEl.innerHTML = `
|
||||||
|
<div class="bank-row"><span>${bankHolderLabel}</span><span>${bankverbindung.kontoinhaber}</span></div>
|
||||||
|
<div class="bank-row"><span>${bankIbanLabel}</span><span>${bankverbindung.iban}</span></div>
|
||||||
|
${bankverbindung.bic ? `<div class="bank-row"><span>${bankBicLabel}</span><span>${bankverbindung.bic}</span></div>` : ""}
|
||||||
|
${bankverbindung.bank ? `<div class="bank-row"><span>${bankBankNameLabel}</span><span>${bankverbindung.bank}</span></div>` : ""}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
bankDetailsEl.innerHTML = `<p class="small">${bankPlaceholderLabel}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById("coupon-apply").addEventListener("click", () => {
|
document.getElementById("coupon-apply").addEventListener("click", () => {
|
||||||
const input = document.getElementById("coupon-input");
|
const input = document.getElementById("coupon-input");
|
||||||
const code = input.value.trim();
|
const code = input.value.trim();
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ const t = useTranslations(lang);
|
|||||||
<span>Klarna</span>
|
<span>Klarna</span>
|
||||||
<input type="radio" name="pay" value="klarna" />
|
<input type="radio" name="pay" value="klarna" />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="pay-option" style="--brand-color:#ff9838; --brand-bg:#241f3d;">
|
||||||
|
<span class="pay-icon pay-icon-cc" style="background:linear-gradient(160deg, #2a2a3d, #14141f);">
|
||||||
|
<span class="cc-dot cc-dot-a"></span><span class="cc-dot cc-dot-b"></span>
|
||||||
|
</span>
|
||||||
|
<span>{t.checkout.creditCard}<span class="pay-sub">{t.checkout.creditCardSub}</span></span>
|
||||||
|
<input type="radio" name="pay" value="kreditkarte" />
|
||||||
|
</label>
|
||||||
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
||||||
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
||||||
<span>{t.checkout.bankTransfer}</span>
|
<span>{t.checkout.bankTransfer}</span>
|
||||||
@@ -39,6 +46,35 @@ const t = useTranslations(lang);
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-connect">
|
||||||
|
<div class="pay-panel" data-panel="paypal">
|
||||||
|
<p>{t.checkout.payPalHint}</p>
|
||||||
|
<div id="paypal-button-container"></div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="klarna" hidden>
|
||||||
|
<p>{t.checkout.klarnaHint}</p>
|
||||||
|
<button type="button" class="btn btn-outline pay-connect-btn" id="klarna-connect">{t.checkout.klarnaConnect}</button>
|
||||||
|
<p class="pay-connect-status" id="klarna-status"></p>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="kreditkarte" hidden>
|
||||||
|
<p>{t.checkout.cardHint}</p>
|
||||||
|
<div class="card-fields">
|
||||||
|
<div>
|
||||||
|
<label for="cc-number">{t.checkout.cardNumber}</label>
|
||||||
|
<input type="text" id="cc-number" inputmode="numeric" placeholder="1234 5678 9012 3456" maxlength="19" />
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-2">
|
||||||
|
<div><label for="cc-expiry">{t.checkout.cardExpiry}</label><input type="text" id="cc-expiry" placeholder="MM/YY" maxlength="5" /></div>
|
||||||
|
<div><label for="cc-cvc">{t.checkout.cardCvc}</label><input type="text" id="cc-cvc" inputmode="numeric" placeholder="123" maxlength="4" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="ueberweisung" hidden>
|
||||||
|
<p>{t.checkout.bankHintReal}</p>
|
||||||
|
<div class="bank-details" id="bank-details"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
||||||
<div class="checkout-split-col">
|
<div class="checkout-split-col">
|
||||||
@@ -101,12 +137,12 @@ const t = useTranslations(lang);
|
|||||||
</section>
|
</section>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/checkout/danke/", checkoutLang: lang, discountLabel: t.cart.discount, couponInvalid: t.cart.couponInvalid, couponAppliedTemplate: t.cart.couponApplied("__C__"), couponRemoveLabel: t.cart.couponRemove }}>
|
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/checkout/danke/", checkoutLang: lang, discountLabel: t.cart.discount, couponInvalid: t.cart.couponInvalid, couponAppliedTemplate: t.cart.couponApplied("__C__"), couponRemoveLabel: t.cart.couponRemove, klarnaConnectLabel: t.checkout.klarnaConnect, klarnaConnectingLabel: t.checkout.klarnaConnecting, klarnaConnectedLabel: t.checkout.klarnaConnected, bankHolderLabel: t.checkout.bankHolder, bankIbanLabel: t.checkout.bankIban, bankBicLabel: t.checkout.bankBic, bankBankNameLabel: t.checkout.bankBankName, bankPlaceholderLabel: t.checkout.bankPlaceholder }}>
|
||||||
// WICHTIG: define:vars-Skripte werden von Astro in ein IIFE gepackt (kein ES-Modul) — echte
|
// WICHTIG: define:vars-Skripte werden von Astro in ein IIFE gepackt (kein ES-Modul) — echte
|
||||||
// `import`-Anweisungen würden hier zur Laufzeit mit "Cannot use import statement outside a
|
// `import`-Anweisungen würden hier zur Laufzeit mit "Cannot use import statement outside a
|
||||||
// module" fehlschlagen. Deshalb hier nur die vom Server gerenderten Werte auf window ablegen,
|
// module" fehlschlagen. Deshalb hier nur die vom Server gerenderten Werte auf window ablegen,
|
||||||
// die eigentliche Logik läuft im separaten <script type="module"> darunter.
|
// die eigentliche Logik läuft im separaten <script type="module"> darunter.
|
||||||
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel };
|
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel };
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../scripts/cart";
|
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../scripts/cart";
|
||||||
@@ -114,13 +150,15 @@ const t = useTranslations(lang);
|
|||||||
import { products } from "../../data/products";
|
import { products } from "../../data/products";
|
||||||
import { berechneVersandkosten } from "../../data/versand";
|
import { berechneVersandkosten } from "../../data/versand";
|
||||||
import { effektiverZeilenpreis } from "../../data/rabatt";
|
import { effektiverZeilenpreis } from "../../data/rabatt";
|
||||||
|
import { bankverbindung, bankverbindungVollstaendig } from "../../data/bankverbindung";
|
||||||
|
|
||||||
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel } = window.__checkoutVars;
|
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel } = window.__checkoutVars;
|
||||||
|
|
||||||
const summary = document.getElementById("checkout-summary");
|
const summary = document.getElementById("checkout-summary");
|
||||||
const landSelect = document.getElementById("land");
|
const landSelect = document.getElementById("land");
|
||||||
const cart = getCart();
|
const cart = getCart();
|
||||||
const subtotal = cartTotal();
|
const subtotal = cartTotal();
|
||||||
|
let currentTotal = 0;
|
||||||
|
|
||||||
function renderSummary() {
|
function renderSummary() {
|
||||||
const land = landSelect.value;
|
const land = landSelect.value;
|
||||||
@@ -128,6 +166,7 @@ import { effektiverZeilenpreis } from "../../data/rabatt";
|
|||||||
const coupon = appliedCoupon();
|
const coupon = appliedCoupon();
|
||||||
const discount = couponDiscount(subtotal);
|
const discount = couponDiscount(subtotal);
|
||||||
const total = Math.max(0, subtotal - discount) + shipping;
|
const total = Math.max(0, subtotal - discount) + shipping;
|
||||||
|
currentTotal = total;
|
||||||
|
|
||||||
summary.innerHTML = `
|
summary.innerHTML = `
|
||||||
${cart.map((i) => {
|
${cart.map((i) => {
|
||||||
@@ -155,6 +194,76 @@ import { effektiverZeilenpreis } from "../../data/rabatt";
|
|||||||
renderSummary();
|
renderSummary();
|
||||||
landSelect.addEventListener("change", renderSummary);
|
landSelect.addEventListener("change", renderSummary);
|
||||||
|
|
||||||
|
// Zahlungsart-Auswahl: pro Methode ein Panel, nur die gewählte ist sichtbar. Macht die
|
||||||
|
// Auswahl sofort "aktionabel" statt ein reines Formularfeld zu sein.
|
||||||
|
const payPanels = document.querySelectorAll(".pay-panel");
|
||||||
|
function showPayPanel(method) {
|
||||||
|
payPanels.forEach((p) => { p.hidden = p.dataset.panel !== method; });
|
||||||
|
}
|
||||||
|
document.querySelectorAll('input[name="pay"]').forEach((radio) => {
|
||||||
|
radio.addEventListener("change", () => showPayPanel(radio.value));
|
||||||
|
});
|
||||||
|
const initialPay = document.querySelector('input[name="pay"]:checked');
|
||||||
|
if (initialPay) showPayPanel(initialPay.value);
|
||||||
|
|
||||||
|
// PayPal: echte PayPal Smart Buttons über das offizielle JS-SDK (Sandbox-Client-ID "sb" —
|
||||||
|
// kostenlos, ohne eigenes Konto testbar). Klick öffnet den echten PayPal-Login-Popup. Für den
|
||||||
|
// Live-Betrieb muss hier nur "sb" durch VanVans echte (kostenlose) PayPal-Business-Client-ID
|
||||||
|
// ersetzt werden, siehe developer.paypal.com.
|
||||||
|
let paypalLoaded = false;
|
||||||
|
function loadPayPalButtons() {
|
||||||
|
if (paypalLoaded || !document.getElementById("paypal-button-container")) return;
|
||||||
|
paypalLoaded = true;
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://www.paypal.com/sdk/js?client-id=sb¤cy=EUR&intent=capture";
|
||||||
|
script.onload = () => {
|
||||||
|
if (!window.paypal) return;
|
||||||
|
window.paypal.Buttons({
|
||||||
|
style: { layout: "vertical", color: "blue", shape: "pill", label: "paypal" },
|
||||||
|
createOrder: (data, actions) => actions.order.create({
|
||||||
|
purchase_units: [{ amount: { value: Math.max(0.01, currentTotal).toFixed(2), currency_code: "EUR" } }],
|
||||||
|
}),
|
||||||
|
onApprove: (data, actions) => actions.order.capture().then(() => { location.href = thankYouPath; }),
|
||||||
|
}).render("#paypal-button-container");
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
loadPayPalButtons();
|
||||||
|
|
||||||
|
// Klarna: echtes "Verbinden" braucht eine serverseitige Session mit VanVans Klarna-Händlerkonto
|
||||||
|
// (Phase 2, Cloudflare Worker). Bis dahin ein sauber gestalteter Demo-Verbindungsablauf, damit
|
||||||
|
// die Oberfläche schon fertig aussieht und 1:1 austauschbar ist, sobald die Anbindung steht.
|
||||||
|
const klarnaBtn = document.getElementById("klarna-connect");
|
||||||
|
const klarnaStatus = document.getElementById("klarna-status");
|
||||||
|
if (klarnaBtn) {
|
||||||
|
klarnaBtn.addEventListener("click", () => {
|
||||||
|
klarnaBtn.disabled = true;
|
||||||
|
klarnaBtn.textContent = klarnaConnectingLabel;
|
||||||
|
setTimeout(() => {
|
||||||
|
klarnaBtn.textContent = klarnaConnectLabel;
|
||||||
|
klarnaBtn.disabled = false;
|
||||||
|
klarnaStatus.textContent = "✅ " + klarnaConnectedLabel;
|
||||||
|
}, 1100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banküberweisung (Vorkasse): braucht KEINE externe Anbindung — zeigt einfach VanVans echte,
|
||||||
|
// im Adminbereich hinterlegte Kontodaten an. Das ist die einzige der vier Zahlungsarten, die
|
||||||
|
// schon zu 100% "fertig" funktioniert.
|
||||||
|
const bankDetailsEl = document.getElementById("bank-details");
|
||||||
|
if (bankDetailsEl) {
|
||||||
|
if (bankverbindungVollstaendig(bankverbindung)) {
|
||||||
|
bankDetailsEl.innerHTML = `
|
||||||
|
<div class="bank-row"><span>${bankHolderLabel}</span><span>${bankverbindung.kontoinhaber}</span></div>
|
||||||
|
<div class="bank-row"><span>${bankIbanLabel}</span><span>${bankverbindung.iban}</span></div>
|
||||||
|
${bankverbindung.bic ? `<div class="bank-row"><span>${bankBicLabel}</span><span>${bankverbindung.bic}</span></div>` : ""}
|
||||||
|
${bankverbindung.bank ? `<div class="bank-row"><span>${bankBankNameLabel}</span><span>${bankverbindung.bank}</span></div>` : ""}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
bankDetailsEl.innerHTML = `<p class="small">${bankPlaceholderLabel}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById("coupon-apply").addEventListener("click", () => {
|
document.getElementById("coupon-apply").addEventListener("click", () => {
|
||||||
const input = document.getElementById("coupon-input");
|
const input = document.getElementById("coupon-input");
|
||||||
const code = input.value.trim();
|
const code = input.value.trim();
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ const t = useTranslations(lang);
|
|||||||
<span>Klarna</span>
|
<span>Klarna</span>
|
||||||
<input type="radio" name="pay" value="klarna" />
|
<input type="radio" name="pay" value="klarna" />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="pay-option" style="--brand-color:#ff9838; --brand-bg:#241f3d;">
|
||||||
|
<span class="pay-icon pay-icon-cc" style="background:linear-gradient(160deg, #2a2a3d, #14141f);">
|
||||||
|
<span class="cc-dot cc-dot-a"></span><span class="cc-dot cc-dot-b"></span>
|
||||||
|
</span>
|
||||||
|
<span>{t.checkout.creditCard}<span class="pay-sub">{t.checkout.creditCardSub}</span></span>
|
||||||
|
<input type="radio" name="pay" value="kreditkarte" />
|
||||||
|
</label>
|
||||||
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
||||||
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
||||||
<span>{t.checkout.bankTransfer}</span>
|
<span>{t.checkout.bankTransfer}</span>
|
||||||
@@ -39,6 +46,35 @@ const t = useTranslations(lang);
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-connect">
|
||||||
|
<div class="pay-panel" data-panel="paypal">
|
||||||
|
<p>{t.checkout.payPalHint}</p>
|
||||||
|
<div id="paypal-button-container"></div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="klarna" hidden>
|
||||||
|
<p>{t.checkout.klarnaHint}</p>
|
||||||
|
<button type="button" class="btn btn-outline pay-connect-btn" id="klarna-connect">{t.checkout.klarnaConnect}</button>
|
||||||
|
<p class="pay-connect-status" id="klarna-status"></p>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="kreditkarte" hidden>
|
||||||
|
<p>{t.checkout.cardHint}</p>
|
||||||
|
<div class="card-fields">
|
||||||
|
<div>
|
||||||
|
<label for="cc-number">{t.checkout.cardNumber}</label>
|
||||||
|
<input type="text" id="cc-number" inputmode="numeric" placeholder="1234 5678 9012 3456" maxlength="19" />
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-2">
|
||||||
|
<div><label for="cc-expiry">{t.checkout.cardExpiry}</label><input type="text" id="cc-expiry" placeholder="MM/YY" maxlength="5" /></div>
|
||||||
|
<div><label for="cc-cvc">{t.checkout.cardCvc}</label><input type="text" id="cc-cvc" inputmode="numeric" placeholder="123" maxlength="4" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="ueberweisung" hidden>
|
||||||
|
<p>{t.checkout.bankHintReal}</p>
|
||||||
|
<div class="bank-details" id="bank-details"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
||||||
<div class="checkout-split-col">
|
<div class="checkout-split-col">
|
||||||
@@ -103,7 +139,7 @@ const t = useTranslations(lang);
|
|||||||
|
|
||||||
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/en/checkout/danke/", checkoutLang: lang }}>
|
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/en/checkout/danke/", checkoutLang: lang }}>
|
||||||
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
||||||
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel };
|
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel };
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
||||||
@@ -111,13 +147,15 @@ const t = useTranslations(lang);
|
|||||||
import { products } from "../../../data/products";
|
import { products } from "../../../data/products";
|
||||||
import { berechneVersandkosten } from "../../../data/versand";
|
import { berechneVersandkosten } from "../../../data/versand";
|
||||||
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
||||||
|
import { bankverbindung, bankverbindungVollstaendig } from "../../../data/bankverbindung";
|
||||||
|
|
||||||
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel } = window.__checkoutVars;
|
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel } = window.__checkoutVars;
|
||||||
|
|
||||||
const summary = document.getElementById("checkout-summary");
|
const summary = document.getElementById("checkout-summary");
|
||||||
const landSelect = document.getElementById("land");
|
const landSelect = document.getElementById("land");
|
||||||
const cart = getCart();
|
const cart = getCart();
|
||||||
const subtotal = cartTotal();
|
const subtotal = cartTotal();
|
||||||
|
let currentTotal = 0;
|
||||||
|
|
||||||
function renderSummary() {
|
function renderSummary() {
|
||||||
const land = landSelect.value;
|
const land = landSelect.value;
|
||||||
@@ -125,6 +163,7 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
const coupon = appliedCoupon();
|
const coupon = appliedCoupon();
|
||||||
const discount = couponDiscount(subtotal);
|
const discount = couponDiscount(subtotal);
|
||||||
const total = Math.max(0, subtotal - discount) + shipping;
|
const total = Math.max(0, subtotal - discount) + shipping;
|
||||||
|
currentTotal = total;
|
||||||
|
|
||||||
summary.innerHTML = `
|
summary.innerHTML = `
|
||||||
${cart.map((i) => {
|
${cart.map((i) => {
|
||||||
@@ -152,6 +191,76 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
renderSummary();
|
renderSummary();
|
||||||
landSelect.addEventListener("change", renderSummary);
|
landSelect.addEventListener("change", renderSummary);
|
||||||
|
|
||||||
|
// Zahlungsart-Auswahl: pro Methode ein Panel, nur die gewählte ist sichtbar. Macht die
|
||||||
|
// Auswahl sofort "aktionabel" statt ein reines Formularfeld zu sein.
|
||||||
|
const payPanels = document.querySelectorAll(".pay-panel");
|
||||||
|
function showPayPanel(method) {
|
||||||
|
payPanels.forEach((p) => { p.hidden = p.dataset.panel !== method; });
|
||||||
|
}
|
||||||
|
document.querySelectorAll('input[name="pay"]').forEach((radio) => {
|
||||||
|
radio.addEventListener("change", () => showPayPanel(radio.value));
|
||||||
|
});
|
||||||
|
const initialPay = document.querySelector('input[name="pay"]:checked');
|
||||||
|
if (initialPay) showPayPanel(initialPay.value);
|
||||||
|
|
||||||
|
// PayPal: echte PayPal Smart Buttons über das offizielle JS-SDK (Sandbox-Client-ID "sb" —
|
||||||
|
// kostenlos, ohne eigenes Konto testbar). Klick öffnet den echten PayPal-Login-Popup. Für den
|
||||||
|
// Live-Betrieb muss hier nur "sb" durch VanVans echte (kostenlose) PayPal-Business-Client-ID
|
||||||
|
// ersetzt werden, siehe developer.paypal.com.
|
||||||
|
let paypalLoaded = false;
|
||||||
|
function loadPayPalButtons() {
|
||||||
|
if (paypalLoaded || !document.getElementById("paypal-button-container")) return;
|
||||||
|
paypalLoaded = true;
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://www.paypal.com/sdk/js?client-id=sb¤cy=EUR&intent=capture";
|
||||||
|
script.onload = () => {
|
||||||
|
if (!window.paypal) return;
|
||||||
|
window.paypal.Buttons({
|
||||||
|
style: { layout: "vertical", color: "blue", shape: "pill", label: "paypal" },
|
||||||
|
createOrder: (data, actions) => actions.order.create({
|
||||||
|
purchase_units: [{ amount: { value: Math.max(0.01, currentTotal).toFixed(2), currency_code: "EUR" } }],
|
||||||
|
}),
|
||||||
|
onApprove: (data, actions) => actions.order.capture().then(() => { location.href = thankYouPath; }),
|
||||||
|
}).render("#paypal-button-container");
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
loadPayPalButtons();
|
||||||
|
|
||||||
|
// Klarna: echtes "Verbinden" braucht eine serverseitige Session mit VanVans Klarna-Händlerkonto
|
||||||
|
// (Phase 2, Cloudflare Worker). Bis dahin ein sauber gestalteter Demo-Verbindungsablauf, damit
|
||||||
|
// die Oberfläche schon fertig aussieht und 1:1 austauschbar ist, sobald die Anbindung steht.
|
||||||
|
const klarnaBtn = document.getElementById("klarna-connect");
|
||||||
|
const klarnaStatus = document.getElementById("klarna-status");
|
||||||
|
if (klarnaBtn) {
|
||||||
|
klarnaBtn.addEventListener("click", () => {
|
||||||
|
klarnaBtn.disabled = true;
|
||||||
|
klarnaBtn.textContent = klarnaConnectingLabel;
|
||||||
|
setTimeout(() => {
|
||||||
|
klarnaBtn.textContent = klarnaConnectLabel;
|
||||||
|
klarnaBtn.disabled = false;
|
||||||
|
klarnaStatus.textContent = "✅ " + klarnaConnectedLabel;
|
||||||
|
}, 1100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banküberweisung (Vorkasse): braucht KEINE externe Anbindung — zeigt einfach VanVans echte,
|
||||||
|
// im Adminbereich hinterlegte Kontodaten an. Das ist die einzige der vier Zahlungsarten, die
|
||||||
|
// schon zu 100% "fertig" funktioniert.
|
||||||
|
const bankDetailsEl = document.getElementById("bank-details");
|
||||||
|
if (bankDetailsEl) {
|
||||||
|
if (bankverbindungVollstaendig(bankverbindung)) {
|
||||||
|
bankDetailsEl.innerHTML = `
|
||||||
|
<div class="bank-row"><span>${bankHolderLabel}</span><span>${bankverbindung.kontoinhaber}</span></div>
|
||||||
|
<div class="bank-row"><span>${bankIbanLabel}</span><span>${bankverbindung.iban}</span></div>
|
||||||
|
${bankverbindung.bic ? `<div class="bank-row"><span>${bankBicLabel}</span><span>${bankverbindung.bic}</span></div>` : ""}
|
||||||
|
${bankverbindung.bank ? `<div class="bank-row"><span>${bankBankNameLabel}</span><span>${bankverbindung.bank}</span></div>` : ""}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
bankDetailsEl.innerHTML = `<p class="small">${bankPlaceholderLabel}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById("coupon-apply").addEventListener("click", () => {
|
document.getElementById("coupon-apply").addEventListener("click", () => {
|
||||||
const input = document.getElementById("coupon-input");
|
const input = document.getElementById("coupon-input");
|
||||||
const code = input.value.trim();
|
const code = input.value.trim();
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ const t = useTranslations(lang);
|
|||||||
<span>Klarna</span>
|
<span>Klarna</span>
|
||||||
<input type="radio" name="pay" value="klarna" />
|
<input type="radio" name="pay" value="klarna" />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="pay-option" style="--brand-color:#ff9838; --brand-bg:#241f3d;">
|
||||||
|
<span class="pay-icon pay-icon-cc" style="background:linear-gradient(160deg, #2a2a3d, #14141f);">
|
||||||
|
<span class="cc-dot cc-dot-a"></span><span class="cc-dot cc-dot-b"></span>
|
||||||
|
</span>
|
||||||
|
<span>{t.checkout.creditCard}<span class="pay-sub">{t.checkout.creditCardSub}</span></span>
|
||||||
|
<input type="radio" name="pay" value="kreditkarte" />
|
||||||
|
</label>
|
||||||
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
<label class="pay-option" style="--brand-color:#7fa8c9; --brand-bg:#3b5a76;">
|
||||||
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
<span class="pay-icon pay-icon-emoji" style="background:linear-gradient(160deg, #4d7599, #2c4258);">🏦</span>
|
||||||
<span>{t.checkout.bankTransfer}</span>
|
<span>{t.checkout.bankTransfer}</span>
|
||||||
@@ -39,6 +46,35 @@ const t = useTranslations(lang);
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pay-connect">
|
||||||
|
<div class="pay-panel" data-panel="paypal">
|
||||||
|
<p>{t.checkout.payPalHint}</p>
|
||||||
|
<div id="paypal-button-container"></div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="klarna" hidden>
|
||||||
|
<p>{t.checkout.klarnaHint}</p>
|
||||||
|
<button type="button" class="btn btn-outline pay-connect-btn" id="klarna-connect">{t.checkout.klarnaConnect}</button>
|
||||||
|
<p class="pay-connect-status" id="klarna-status"></p>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="kreditkarte" hidden>
|
||||||
|
<p>{t.checkout.cardHint}</p>
|
||||||
|
<div class="card-fields">
|
||||||
|
<div>
|
||||||
|
<label for="cc-number">{t.checkout.cardNumber}</label>
|
||||||
|
<input type="text" id="cc-number" inputmode="numeric" placeholder="1234 5678 9012 3456" maxlength="19" />
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-2">
|
||||||
|
<div><label for="cc-expiry">{t.checkout.cardExpiry}</label><input type="text" id="cc-expiry" placeholder="MM/YY" maxlength="5" /></div>
|
||||||
|
<div><label for="cc-cvc">{t.checkout.cardCvc}</label><input type="text" id="cc-cvc" inputmode="numeric" placeholder="123" maxlength="4" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay-panel" data-panel="ueberweisung" hidden>
|
||||||
|
<p>{t.checkout.bankHintReal}</p>
|
||||||
|
<div class="bank-details" id="bank-details"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
<div class="checkout-split-divider" aria-hidden="true"><span>🧵</span></div>
|
||||||
<div class="checkout-split-col">
|
<div class="checkout-split-col">
|
||||||
@@ -103,7 +139,7 @@ const t = useTranslations(lang);
|
|||||||
|
|
||||||
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/fr/checkout/danke/", checkoutLang: lang }}>
|
<script define:vars={{ freeLabel: t.checkout.free, totalLabel: t.checkout.total, shippingLabel: t.cart.shipping, emptyCartAlert: t.checkout.emptyCartAlert, thankYouPath: "/fr/checkout/danke/", checkoutLang: lang }}>
|
||||||
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
// WICHTIG: define:vars-Skripte laufen als IIFE, keine "import"-Anweisungen möglich.
|
||||||
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel };
|
window.__checkoutVars = { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel };
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
import { getCart, cartTotal, appliedCoupon, couponDiscount, setCouponCode, clearCoupon } from "../../../scripts/cart";
|
||||||
@@ -111,13 +147,15 @@ const t = useTranslations(lang);
|
|||||||
import { products } from "../../../data/products";
|
import { products } from "../../../data/products";
|
||||||
import { berechneVersandkosten } from "../../../data/versand";
|
import { berechneVersandkosten } from "../../../data/versand";
|
||||||
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
import { effektiverZeilenpreis } from "../../../data/rabatt";
|
||||||
|
import { bankverbindung, bankverbindungVollstaendig } from "../../../data/bankverbindung";
|
||||||
|
|
||||||
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel } = window.__checkoutVars;
|
const { freeLabel, totalLabel, shippingLabel, emptyCartAlert, thankYouPath, checkoutLang, discountLabel, couponInvalid, couponAppliedTemplate, couponRemoveLabel, klarnaConnectLabel, klarnaConnectingLabel, klarnaConnectedLabel, bankHolderLabel, bankIbanLabel, bankBicLabel, bankBankNameLabel, bankPlaceholderLabel } = window.__checkoutVars;
|
||||||
|
|
||||||
const summary = document.getElementById("checkout-summary");
|
const summary = document.getElementById("checkout-summary");
|
||||||
const landSelect = document.getElementById("land");
|
const landSelect = document.getElementById("land");
|
||||||
const cart = getCart();
|
const cart = getCart();
|
||||||
const subtotal = cartTotal();
|
const subtotal = cartTotal();
|
||||||
|
let currentTotal = 0;
|
||||||
|
|
||||||
function renderSummary() {
|
function renderSummary() {
|
||||||
const land = landSelect.value;
|
const land = landSelect.value;
|
||||||
@@ -125,6 +163,7 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
const coupon = appliedCoupon();
|
const coupon = appliedCoupon();
|
||||||
const discount = couponDiscount(subtotal);
|
const discount = couponDiscount(subtotal);
|
||||||
const total = Math.max(0, subtotal - discount) + shipping;
|
const total = Math.max(0, subtotal - discount) + shipping;
|
||||||
|
currentTotal = total;
|
||||||
|
|
||||||
summary.innerHTML = `
|
summary.innerHTML = `
|
||||||
${cart.map((i) => {
|
${cart.map((i) => {
|
||||||
@@ -152,6 +191,76 @@ import { effektiverZeilenpreis } from "../../../data/rabatt";
|
|||||||
renderSummary();
|
renderSummary();
|
||||||
landSelect.addEventListener("change", renderSummary);
|
landSelect.addEventListener("change", renderSummary);
|
||||||
|
|
||||||
|
// Zahlungsart-Auswahl: pro Methode ein Panel, nur die gewählte ist sichtbar. Macht die
|
||||||
|
// Auswahl sofort "aktionabel" statt ein reines Formularfeld zu sein.
|
||||||
|
const payPanels = document.querySelectorAll(".pay-panel");
|
||||||
|
function showPayPanel(method) {
|
||||||
|
payPanels.forEach((p) => { p.hidden = p.dataset.panel !== method; });
|
||||||
|
}
|
||||||
|
document.querySelectorAll('input[name="pay"]').forEach((radio) => {
|
||||||
|
radio.addEventListener("change", () => showPayPanel(radio.value));
|
||||||
|
});
|
||||||
|
const initialPay = document.querySelector('input[name="pay"]:checked');
|
||||||
|
if (initialPay) showPayPanel(initialPay.value);
|
||||||
|
|
||||||
|
// PayPal: echte PayPal Smart Buttons über das offizielle JS-SDK (Sandbox-Client-ID "sb" —
|
||||||
|
// kostenlos, ohne eigenes Konto testbar). Klick öffnet den echten PayPal-Login-Popup. Für den
|
||||||
|
// Live-Betrieb muss hier nur "sb" durch VanVans echte (kostenlose) PayPal-Business-Client-ID
|
||||||
|
// ersetzt werden, siehe developer.paypal.com.
|
||||||
|
let paypalLoaded = false;
|
||||||
|
function loadPayPalButtons() {
|
||||||
|
if (paypalLoaded || !document.getElementById("paypal-button-container")) return;
|
||||||
|
paypalLoaded = true;
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://www.paypal.com/sdk/js?client-id=sb¤cy=EUR&intent=capture";
|
||||||
|
script.onload = () => {
|
||||||
|
if (!window.paypal) return;
|
||||||
|
window.paypal.Buttons({
|
||||||
|
style: { layout: "vertical", color: "blue", shape: "pill", label: "paypal" },
|
||||||
|
createOrder: (data, actions) => actions.order.create({
|
||||||
|
purchase_units: [{ amount: { value: Math.max(0.01, currentTotal).toFixed(2), currency_code: "EUR" } }],
|
||||||
|
}),
|
||||||
|
onApprove: (data, actions) => actions.order.capture().then(() => { location.href = thankYouPath; }),
|
||||||
|
}).render("#paypal-button-container");
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
loadPayPalButtons();
|
||||||
|
|
||||||
|
// Klarna: echtes "Verbinden" braucht eine serverseitige Session mit VanVans Klarna-Händlerkonto
|
||||||
|
// (Phase 2, Cloudflare Worker). Bis dahin ein sauber gestalteter Demo-Verbindungsablauf, damit
|
||||||
|
// die Oberfläche schon fertig aussieht und 1:1 austauschbar ist, sobald die Anbindung steht.
|
||||||
|
const klarnaBtn = document.getElementById("klarna-connect");
|
||||||
|
const klarnaStatus = document.getElementById("klarna-status");
|
||||||
|
if (klarnaBtn) {
|
||||||
|
klarnaBtn.addEventListener("click", () => {
|
||||||
|
klarnaBtn.disabled = true;
|
||||||
|
klarnaBtn.textContent = klarnaConnectingLabel;
|
||||||
|
setTimeout(() => {
|
||||||
|
klarnaBtn.textContent = klarnaConnectLabel;
|
||||||
|
klarnaBtn.disabled = false;
|
||||||
|
klarnaStatus.textContent = "✅ " + klarnaConnectedLabel;
|
||||||
|
}, 1100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banküberweisung (Vorkasse): braucht KEINE externe Anbindung — zeigt einfach VanVans echte,
|
||||||
|
// im Adminbereich hinterlegte Kontodaten an. Das ist die einzige der vier Zahlungsarten, die
|
||||||
|
// schon zu 100% "fertig" funktioniert.
|
||||||
|
const bankDetailsEl = document.getElementById("bank-details");
|
||||||
|
if (bankDetailsEl) {
|
||||||
|
if (bankverbindungVollstaendig(bankverbindung)) {
|
||||||
|
bankDetailsEl.innerHTML = `
|
||||||
|
<div class="bank-row"><span>${bankHolderLabel}</span><span>${bankverbindung.kontoinhaber}</span></div>
|
||||||
|
<div class="bank-row"><span>${bankIbanLabel}</span><span>${bankverbindung.iban}</span></div>
|
||||||
|
${bankverbindung.bic ? `<div class="bank-row"><span>${bankBicLabel}</span><span>${bankverbindung.bic}</span></div>` : ""}
|
||||||
|
${bankverbindung.bank ? `<div class="bank-row"><span>${bankBankNameLabel}</span><span>${bankverbindung.bank}</span></div>` : ""}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
bankDetailsEl.innerHTML = `<p class="small">${bankPlaceholderLabel}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById("coupon-apply").addEventListener("click", () => {
|
document.getElementById("coupon-apply").addEventListener("click", () => {
|
||||||
const input = document.getElementById("coupon-input");
|
const input = document.getElementById("coupon-input");
|
||||||
const code = input.value.trim();
|
const code = input.value.trim();
|
||||||
|
|||||||
@@ -1057,6 +1057,45 @@ a:focus-visible, button:focus-visible {
|
|||||||
background-blend-mode: overlay;
|
background-blend-mode: overlay;
|
||||||
}
|
}
|
||||||
.pay-option .pay-icon.pay-icon-emoji { font-size: 1.7rem; font-style: normal; }
|
.pay-option .pay-icon.pay-icon-emoji { font-size: 1.7rem; font-style: normal; }
|
||||||
|
|
||||||
|
/* Kreditkarte: zwei überlappende Kreise (Visa/Mastercard-Anmutung) statt einem Buchstaben. */
|
||||||
|
.pay-icon-cc { position: relative; }
|
||||||
|
.pay-icon-cc .cc-dot { position: absolute; width: 24px; height: 24px; border-radius: 50%; top: 50%; transform: translateY(-50%); }
|
||||||
|
.pay-icon-cc .cc-dot-a { left: 8px; background: #eb5b3c; }
|
||||||
|
.pay-icon-cc .cc-dot-b { left: 20px; background: #f7b73c; mix-blend-mode: screen; }
|
||||||
|
.pay-option .pay-sub { display: block; font-weight: 400; font-size: 0.8rem; color: var(--c-text-muted); margin-top: 0.1em; }
|
||||||
|
|
||||||
|
/* Ausklappbarer "Verbinden"-Bereich unter der Zahlungsart-Auswahl: pro Methode ein Panel, nur
|
||||||
|
das zur ausgewählten Zahlungsart passende ist sichtbar. Macht die Auswahl sofort "aktionabel"
|
||||||
|
statt nur ein reines Auswahlfeld zu sein. */
|
||||||
|
.pay-connect {
|
||||||
|
margin-top: 1.1rem;
|
||||||
|
padding: 1.1rem 1.2rem;
|
||||||
|
border-radius: var(--radius-m);
|
||||||
|
background: color-mix(in srgb, var(--c-accent) 6%, var(--c-anthracite));
|
||||||
|
border: 1px solid color-mix(in srgb, var(--c-accent) 25%, transparent);
|
||||||
|
}
|
||||||
|
.pay-panel[hidden] { display: none; }
|
||||||
|
.pay-panel p { margin: 0 0 0.8em; color: var(--c-text-muted); font-size: 0.88rem; }
|
||||||
|
.pay-connect-btn { width: 100%; }
|
||||||
|
.pay-connect-btn[disabled] { opacity: 0.75; cursor: default; }
|
||||||
|
.pay-connect-status { margin: 0.7em 0 0; font-size: 0.88rem; color: var(--c-accent); font-weight: 600; }
|
||||||
|
|
||||||
|
/* Inline-Kartenformular (Kreditkarte) */
|
||||||
|
.card-fields { display: grid; gap: 0.7rem; }
|
||||||
|
.card-fields label { display: block; font-size: 0.8rem; color: var(--c-text-muted); margin-bottom: 0.3rem; }
|
||||||
|
.card-fields input { font-variant-numeric: tabular-nums; letter-spacing: 0.03em; }
|
||||||
|
|
||||||
|
/* Bankverbindung (Vorkasse) — echte, direkt aus dem Adminbereich gespeiste Kontodaten. */
|
||||||
|
.bank-details {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
}
|
||||||
|
.bank-details .bank-row { display: flex; justify-content: space-between; gap: 1em; padding: 0.4em 0; border-bottom: 1px dashed rgba(244, 241, 247, 0.14); }
|
||||||
|
.bank-details .bank-row:last-child { border-bottom: none; }
|
||||||
|
.bank-details .bank-row span:first-child { color: var(--c-text-muted); }
|
||||||
|
.bank-details .bank-row span:last-child { font-weight: 700; letter-spacing: 0.02em; }
|
||||||
.pay-option input[type="radio"] {
|
.pay-option input[type="radio"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
|
|||||||
Reference in New Issue
Block a user