Aller au contenu

Vue 3

Provider, composables, props d'intégration et configuration Nuxt associée.

@wajub/vue enveloppe @wajub/js avec la syntaxe Vue 3 : un provider qui charge une fois l'environnement d'exécution, cinq composants de champs et quatre composables. L'API de paiement ne change pas. Le comportement de chaque option est présenté dans Checkout hébergé et Champs de paiement. Cette page traite des éléments propres à Vue.

@wajub/vue

Stable · GA

npm

Version
1.5.1
Runtime
Vue 3.3+

Couvre

  • Paiements
  • Liens de paiement

Absent de ce paquet : Facturation, Transferts, Sync, Shield, Taxes.

Installer

@wajub/js est une dépendance homologue, non intégrée. Installez-la donc sur la même ligne. Le package est uniquement ESM et déclare sideEffects: false.

npm install @wajub/vue @wajub/js

Provider

WajubProvider appelle loadWajub() depuis @wajub/js/pure et fournit l'environnement d'exécution avec l'injection de Vue. Un provider couvre toute une sous-arborescence. Placez-le donc au niveau de la mise en page ou de la page, pas autour de chaque composant.

layouts/checkout.vue
<script setup lang="ts">
import { WajubProvider } from '@wajub/vue';
</script>

<template>
  <ClientOnly>
    <WajubProvider>
      <slot />
    </WajubProvider>
  </ClientOnly>
</template>
PropTypeValeur par défautFonction
deferbooleanfalseIgnore le chargement automatique. Laissez-le désactivé : en 1.5.1, rien ne charge ensuite l'environnement d'exécution dans le provider
load-options{ jsOrigin?, jsUrl? }Valeurs du CDNRemplace l'origine de chargement de l'environnement d'exécution

defer ne fonctionne pas en 1.5.1. Il empêche le provider de charger l'environnement d'exécution, et le loadWajub() renvoyé par useLoadWajub() vous renvoie l'environnement sans l'enregistrer dans le provider, si bien que les intégrations et les composants de champs ne se montent jamais. Laissez defer désactivé : le provider commence alors le chargement dès son montage.

Composables

La forme sûre
<script setup lang="ts">
import { useWajubOptional } from '@wajub/vue';

const props = defineProps<{ sessionId: string }>();
const runtime = useWajubOptional();

function upgrade() {
  runtime.value?.wajub.open({ sessionId: props.sessionId, onSuccess: onUpgraded });
}
</script>

<template>
  <button :disabled="!runtime" @click="upgrade">Upgrade plan</button>
</template>

C'est la ref qui fait fonctionner ce bouton : elle vaut null lorsque setup s'exécute, car le provider ne commence le chargement qu'une fois monté, puis elle se remplit à l'arrivée de l'environnement d'exécution. Lisez runtime.value dans le script. Le template lit directement sa valeur : !runtime y suffit.

ComposableValeur renvoyéeRemarques
useWajub(){ wajub, Wajub, WajubError }Génère une erreur pendant le chargement, en cas d'échec ou sans environnement
useWajubOptional()Une ref en lecture seule de la même valeur, null tant que l'environnement n'est pas chargéSûr pendant le SSR et avant l'arrivée du script
useLoadWajub(){ runtime, loading, error, loadWajub }Les trois premiers sont des refs. Son loadWajub() ne met pas le provider à jour
useConfirmPayment(sessionId){ confirm, isConfirming }isConfirming est une ref. Envoie un composant de champ monté

useWajubContext() renvoie les mêmes refs { runtime, loading, error } si vous préférez créer votre propre composable. WAJUB_INJECTION_KEY est la clé utilisée par le provider.

CheckoutEmbed

Le checkout hébergé dans votre propre mise en page. Contrairement aux autres frameworks, les props forment une liste fermée : session-id, class, style, min-height, locale, embed-origin, theme, appearance, layout, loading-text, show-loading et les onze callbacks.

pages/checkout.vue
<script setup lang="ts">
import { CheckoutEmbed } from '@wajub/vue';

defineProps<{ sessionId: string }>();
</script>

<template>
  <CheckoutEmbed
    :key="sessionId"
    :session-id="sessionId"
    layout="tabs"
    :min-height="480"
    @success="navigateTo('/order/complete')"
    @error="(error) => console.error(error.code, error.message)"
  />
</template>

Chaque callback est déclaré comme prop. @success et :on-success sont donc équivalents. Vue convertit le listener en prop pour vous.

PropTypeValeur par défautFonction
session-idstringObligatoireLa valeur authorization_token de POST /payments
classstringaucuneClasse de l'élément conteneur
styleRecord<string, string>aucunStyles en ligne du conteneur
min-heightnumber480Hauteur réservée en pixels pendant le chargement de l'iframe
Changer de thème après le montage
<script setup lang="ts">
import { ref, watch } from 'vue';
import type { CheckoutInstance } from '@wajub/js';
import { CheckoutEmbed } from '@wajub/vue';

const props = defineProps<{ sessionId: string; dark: boolean }>();
const checkout = ref<CheckoutInstance | null>(null);

watch(
  () => props.dark,
  (dark) => checkout.value?.update({ appearance: { colorScheme: dark ? 'dark' : 'light' } }),
);
</script>

<template>
  <CheckoutEmbed
    :key="sessionId"
    :session-id="sessionId"
    @ready="(instance) => (checkout = instance)"
  />
</template>

Champs de paiement

Les cinq composants affichent chacun un groupe de champs : CardComponent, MobileMoneyComponent, WalletComponent, PaymentComponent et AddressComponent. Ils partagent les props de ComponentConfig, avec les props du wrapper ci-dessous. ComponentEmbed est le même composant avec un type explicite lorsque le choix intervient pendant l'exécution.

Votre mise en page et votre bouton
<script setup lang="ts">
import { ref } from 'vue';
import type { ComponentInstance } from '@wajub/js';
import { AddressComponent, PaymentComponent, useConfirmPayment } from '@wajub/vue';

const props = defineProps<{ sessionId: string }>();
const { confirm, isConfirming } = useConfirmPayment(props.sessionId);
const field = ref<ComponentInstance | null>(null);

function pay() {
  if (field.value) confirm(field.value);
}
</script>

<template>
  <AddressComponent :session-id="sessionId" address-mode="shipping" />
  <PaymentComponent
    :session-id="sessionId"
    collect-address="shipping"
    collect-name
    @instance="(instance) => (field = instance)"
  />
  <button :disabled="isConfirming || !field" @click="pay">
    {{ isConfirming ? 'Processing…' : 'Pay now' }}
  </button>
</template>
PropTypeValeur par défautFonction
typeComponentTypeDéfini par l'aliasUniquement sur ComponentEmbed
min-heightnumber200 (card), 240 (mobileMoney), 120 (wallet), 360 (payment), 280 (address)Hauteur réservée pendant le chargement du champ
@instance(instance | null) => voidaucuneSe déclenche au montage, puis avec null au démontage
@ready(instance) => voidaucuneSe déclenche lorsque le champ devient interactif

useConfirmPayment protège contre les doubles envois. Un second clic lorsque isConfirming vaut true est ignoré. Il réussit avec { status } et rejette avec une WajubError, dont confirmation_timeout après 60 secondes.

Les composants de champs se mettent à jour sur place

Contrairement à l'intégration, ils surveillent appearance, locale et layout, puis appellent update() avec les trois valeurs lorsque l'une change. La modification de session-id ou type remonte plutôt le champ.

Nuxt

La session est créée sur votre serveur. Aucun élément de ce package ne nécessite ni ne doit recevoir de clé secrète.

server/api/checkout/session.post.ts
import { Wajub } from '@wajub/node';

const wajub = new Wajub({ secretKey: process.env.WAJUB_API_KEY! });

export default defineEventHandler(async (event) => {
  const { cartId } = await readBody(event);

  const payment = await wajub.payments.create(
    {
      amount: 25000,
      currency: 'XAF',
      description: `Cart ${cartId}`,
      customer: { email: '[email protected]' },
      callback: `${process.env.NUXT_PUBLIC_APP_URL}/order/return`,
      metadata: { cart_id: cartId },
    },
    { idempotencyKey: `cart-${cartId}` },
  );

  return { sessionId: payment.authorization_token };
});

Nuxt impose trois autres règles :

  • Placez le checkout dans <ClientOnly>. L'environnement d'exécution nécessite un window. Les composables renvoient null au lieu de générer une erreur pendant le rendu serveur.
  • Placez WajubProvider dans une mise en page pour éviter qu'une navigation dans le flux de checkout recharge l'environnement d'exécution.
  • Récupérez la session depuis server/api/ et transmettez le jeton comme prop.

Éléments exportés par le package

ExportDescription
WajubProviderCharge une fois l'environnement d'exécution pour la sous-arborescence
CheckoutEmbedCheckout hébergé en ligne
CardComponent, MobileMoneyComponent, WalletComponent, PaymentComponent, AddressComponentUn groupe de champs chacun
ComponentEmbedLe même composant avec le type transmis comme prop
useWajub, useWajubOptional, useLoadWajubDonnent accès à l'environnement d'exécution
useConfirmPaymentEnvoie un composant de champ
WAJUB_INJECTION_KEY, useWajubContextInjection brute pour votre propre composable

Les types sont inclus : WajubProviderProps, CheckoutEmbedProps, ComponentEmbedProps, WajubContextValue et, à partir de la version 1.6.0, WajubRuntimeRef, le type renvoyé par useWajubOptional(), avec tous les exports de @wajub/js.

Que pensez-vous de ce contenu ?