React ve Next.js’te reddedilen ödemelere ve değişen fiyatlara dayanan tek sayfalık bir ödeme akışı nasıl kurulur
Bir ödeme formu kolaydır. Reddedilen ödemeler, 3-D Secure, Öde’den önce değişen fiyatlar ve hiç yanıt vermeyen ödemeler değildir. React ve Next.js’te tek sayfalık bir ödeme akışı.
Preet Suthar · · 6 dk okuma
- React
- Next.js
- E-commerce
- Payments
Çoğu ödeme sayfası eğitimi bir formla ve Stripe’ı çağıran bir Öde düğmesiyle biter. O kısım ilk denemede çalışır. Sipariş kaybettiren şey etrafındaki her şeydir: reddedilen kart, 3-D Secure doğrulaması isteyen banka, posta koduna göre değişen kargo ücreti, hiç geri dönmeyen istek ve Öde’ye ikinci kez basan müşteri.
React ve Next.js’te tek sayfalık bir ödeme akışını böyle yapılandırıyorum: önemli olan durumlar ve her biri için küçük bir kod parçası. shadcn/ui ya da başka herhangi bir bileşen setiyle çalışır. Zor olan kısım stil değil, akıştır.
Tek sayfa, katlanan üç adım
Tek sayfalık bir ödeme akışı her şeyi görünür tutar: adımlar arasında sayfa yüklemesi olmaz ve tarayıcının Geri düğmesi yarım bir formu çöpe atamaz. Ama tek bir uzun form bir duvardır. Çözüm aynı sayfada üç adımdır: iletişim, teslimat ve ödeme; ve aynı anda yalnızca biri açıktır.
Bir adım bittiğinde bir özet satırına katlanır; böylece tamamlanmış bir ödeme sayfası bir fiş gibi okunur:
Arkasındaki durum küçüktür. Tamamlanan adımların listesini tutun ve açık olanı ondan türetin:
İki ayrıntı doğru hissettirir. Biri Değiştir’e bastığında odağı açılan adımın başlığına taşıyın; yoksa klavye ve ekran okuyucu kullanıcıları artık var olmayan bir düğmede kalır. Müşteri oturum açmışsa da iletişimi atlayın ve varsayılan adresiyle teslimattan başlayın.
Geniş ekranlarda sipariş özeti formun yanında durur. Telefonlarda formun üstünde, toplamı göstermeye devam eden bir "Sipariş özetini göster" çubuğuna katlanır, çünkü toplam insanların sürekli kontrol ettiği tek rakamdır.
Blur’da doğrula, Öde’de özetle
Bir alanın hatasını müşteri o alandan ayrıldığında gösterin, sonra yazdıkça canlı olarak güncelleyin ki düzeltildiği anda kaybolsun. İlk kez yazarken asla göstermeyin.
Form geçerli olana kadar Öde’yi devre dışı bırakmayın. Devre dışı bir düğme kimseye neyin eksik olduğunu söyleyemez. Basmalarına izin verin, sonra en üste her sorunu listeleyen tek bir özet koyun, her maddeyi kendi alanına bağlayın ve odağı özete taşıyın. GOV.UK Design System’ın hata özeti bu desen için iyi bir referanstır.
Ücretler ve vergiler adresi takip eder
Kargo ücretleri ve vergi adrese bağlıdır, bu yüzden ancak adres tamamlandığında yüklenebilirler. Yazmada kısa bir duraklama bekleyin, adres yeniden değiştiğinde önceki isteği iptal edin ve özette eskimiş bir rakam yerine "Hesaplanıyor…" gösterin.
Yeni ücretler geldiğinde, seçilen ücret hâlâ sunuluyorsa onu koruyun. Sunulmuyorsa en ucuzunu seçin ve bunu söyleyin: "Ekspres bu adres için kullanılamıyor." Yöntemi sessizce değiştirmek, insanların seçmedikleri kargo için ödeme yapmasına yol açar.
Hızlı ödeme önce gelir
Apple Pay, Google Pay, Shop Pay ve PayPal formun tamamının yerini alır; bu yüzden yerleri en üst, iletişim bölümünün üstüdür ve altlarında bir "Ya da kartla öde" ayırıcısı bulunur. Onları Öde düğmesinin yanına koymak, müşterinin daha hızlı yolu gördüğünde adresini çoktan yazmış olması demektir. Yalnızca tarayıcının gerçekten kullanabildiği cüzdanları render edin. Stripe’ın Express Checkout Element’i ve benzer SDK’lar bunu sizin için belirler.
Öde bir boolean değil, bir durum makinesidir
isSubmitting, Öde’den sonra olanları tanımlayamaz. Bunun yerine sunucunun yanıtına bir tip verin:
Sonra her durumu bilinçli olarak ele alın.
Öde iki kez çalışamaz. Çift tıklama, React yeniden render etmeden önce iki işleyiciyi tetikler; bu yüzden disabled={pending} kontrolü yeterli değildir. Bir ref ile koruyun ve sipariş verilirken Değiştir düğmelerini kilitleyin ki sepet ödemenin altından kaymasın.
Her denemeye bir idempotency anahtarı verilir. Öde’ye basıldığında crypto.randomUUID() ile oluşturun ve ödeme isteğiyle birlikte gönderin. Stripe ve çoğu ödeme API’si bunu kabul eder; aynı anahtarla yeniden denenen bir istek iki kez ücret çekemez.
Ödeme sırasında sayfadan ayrılmadan önce sorulur. Ödeme sürerken bir beforeunload dinleyicisi ekleyin ve ödeme sonuçlanınca kaldırın.
Reddedilen ödemelerin "Bir şeyler ters gitti" değil, kelimelere ihtiyacı var
Reddedilen ödeme, ödeme sayfasındaki en yaygın hata ve metni en kötü yazılan durumdur. Geri aldığınız kodları insanlara ne yapacaklarını söyleyen cümlelere eşleyin, odağı mesaja taşıyın ve kart bilgilerini dolu tutun:
requires_action bir hata değildir. Bankanın 3-D Secure istediği anlamına gelir; bu, güçlü müşteri kimlik doğrulaması kapsamında Avrupa’da olağan bir durumdur. İşleniyor durumunu koruyun, bankanın doğrulamasını "Bankanızla onaylayın" başlıklı bir diyalogda açın ve sonuçlandığında devam edin.
Fiyat sepetten beri değiştiğinde
Fiyatlar, stok ve indirimler sepet ile Öde arasında değişebilir. Müşterinin gördüğü toplamı siparişle birlikte gönderin, sunucuda yeniden fiyatlayın ve farklıysa ücret çekmeyi reddedin:
İstemcide özeti güncelleyin, eski toplamın üstünü çizin ve her değişikliği sade bir dille listeleyin, örneğin "Ring vase artık $74, önceden $68 idi." Müşteri yeni tutarla yeniden Öde’ye basar. Ödeme sırasında tükenen bir ürün de aynı şekilde çalışır: onu toplamdan çıkarın, işaretleyin ve kaldırmalarına ya da onsuz devam etmelerine izin verin.
Ödeme hiç yanıt vermediğinde
Bazen istek takılı kalır. Zaman aşımından sonra gösterebileceğiniz en kötü şey "Tekrar dene"dir, çünkü ilk ücret çekimi gerçekleşmiş olabilir. Makul bir beklemenin ardından "Ödeme durumunuz kontrol ediliyor…" deyin ve bir sipariş olup olmadığını öğrenene kadar aynı idempotency anahtarıyla bir durum endpoint’ini yoklayın. Yeni bir denemeyi ancak sunucu eskisinin başarısız olduğunu söylediğinde sunun.
Bir kontrol listesi
- Adımlar özet satırlarına katlanır ve Değiştir, odağı yeniden açılan adıma taşır.
- Blur’da hatalar, Öde’de tek bir bağlantılı özet, devre dışı Öde düğmesi yok.
- Ücretler ve vergi tam bir adres bekler, eskimiş istekleri iptal eder ve asla eskimiş bir toplam göstermez.
- Hızlı ödeme cüzdanları en üstte; yalnızca tarayıcının desteklediği olanlar.
- Öde’nin etrafında bir ref koruması, bir idempotency anahtarı ve bir
beforeunloaduyarısı. - Her ret kodu için özel metin, form dolu kalırken.
- 3-D Secure bir hata değil, bir adım.
- Değişen fiyatlar ve tükenen ürünler ödemeyi durdurur ve nedenini açıklar.
- Zaman aşımı, yeniden ödeme teklif etmek yerine durumu kontrol eder.
shadcn/ui ile kurmak
shadcn/ui tüm bunlar için input’ları, radio grupları ve collapsible’ları verir. Yukarıdaki akış kendiniz yazdığınız kısımdır ve işin çoğu odur.
Bunu bir kez, ücretsiz HextaUI bileşenlerinden yapılmış HextaUI Pro’daki Checkout bloğu olarak kurdum. Sepeti ve üç callback’i, onGetRates, onEstimateTax ve onPlaceOrder’ı alır ve yukarıdaki dört sonucu ele alır. onPlaceOrder 20 saniye içinde yanıt vermezse yeniden ödeme teklif etmek yerine aynı idempotency anahtarıyla onCheckStatus’u yoklar. Server action’larla Stripe PaymentIntents, Shopify checkout devri ve Medusa için örneklerle gelir. Cüzdanlar, kartlar, reddedilen ödemeler ve 3-D Secure için Payment bloğunu, teslimat için de Address Form’u kullanır. Her bloğun, herhangi bir karar vermeden önce tıklayarak gezebileceğiniz canlı bir önizlemesi var.
Mağazanız Shopify üzerinde çalışıyorsa, yeniden kurmak yerine Shopify’ın barındırılan ödeme sayfasını kullanın. Özel bir ödeme akışı, ödemeyi kendiniz aldığınızda anlamlıdır.
SSS
Tek sayfalık ödeme, çok adımlı olandan daha mı iyi? Çoğu mağaza için katlanan adımlara sahip tek bir sayfa ikisinin de en iyisini sunar: her şey görünür kalır ve insanlar aynı anda yalnızca bir bölümle uğraşır.
Form geçerli olana kadar Öde düğmesini devre dışı bırakmalı mıyım? Hayır. İnsanların basmasına izin verin ve eksik olanların bir özetini, her alana giden bağlantılarla gösterin.
Çift ücretlendirmeyi nasıl önlerim? İşleyiciyi bir ref ile koruyun, her denemeyle bir idempotency anahtarı gönderin ve zaman aşımına uğrayan bir ödemede insanların yeniden ödemesine izin vermek yerine durumunu kontrol edin.
Apple Pay ve Google Pay nereye konmalı? Ödeme sayfasının en üstüne, iletişim bilgilerinden önce, çünkü formun geri kalanının yerini alırlar.