React Integration

The mypos-online-checkout/react sub-export provides a PaymentForm component and a usePaymentForm hook for React 18+ applications. It keeps the React dependency out of the core server-side package.

React 18+ required. The sub-export uses React hooks and server/client component patterns compatible with React 18 and Next.js 13+.

Import

import { PaymentForm, usePaymentForm } from 'mypos-online-checkout/react'
const { PaymentForm, usePaymentForm } = require('mypos-online-checkout/react')

PaymentForm Component

PaymentForm renders the hidden signed fields and submits the form to the myPOS checkout URL. Pass the checkoutFields object generated server-side.

'use client'

import { PaymentForm } from 'mypos-online-checkout/react'

interface CheckoutPageProps {
  checkoutFields: Record<string, string>
  checkoutUrl: string
}

export function CheckoutPage({ checkoutFields, checkoutUrl }: CheckoutPageProps) {
  return (
    <PaymentForm
      checkoutFields={checkoutFields}
      checkoutUrl={checkoutUrl}
      submitLabel="Pay now"
      className="mt-4"
    />
  )
}
'use client'

import { PaymentForm } from 'mypos-online-checkout/react'

export function CheckoutPage({ checkoutFields, checkoutUrl }) {
  return (
    <PaymentForm
      checkoutFields={checkoutFields}
      checkoutUrl={checkoutUrl}
      submitLabel="Pay now"
      className="mt-4"
    />
  )
}

usePaymentForm Hook

Use usePaymentForm when you need to programmatically trigger form submission or access form state:

'use client'

import { usePaymentForm } from 'mypos-online-checkout/react'

interface ManualCheckoutProps {
  checkoutFields: Record<string, string>
  checkoutUrl: string
}

export function ManualCheckout({ checkoutFields, checkoutUrl }: ManualCheckoutProps) {
  const { formRef, submit, isSubmitting } = usePaymentForm({ checkoutFields, checkoutUrl })

  return (
    <>
      <form ref={formRef} />
      <button onClick={submit} disabled={isSubmitting}>
        {isSubmitting ? 'Redirecting…' : 'Complete payment'}
      </button>
    </>
  )
}
'use client'

import { usePaymentForm } from 'mypos-online-checkout/react'

export function ManualCheckout({ checkoutFields, checkoutUrl }) {
  const { formRef, submit, isSubmitting } = usePaymentForm({ checkoutFields, checkoutUrl })

  return (
    <>
      <form ref={formRef} />
      <button onClick={submit} disabled={isSubmitting}>
        {isSubmitting ? 'Redirecting…' : 'Complete payment'}
      </button>
    </>
  )
}

Next.js Architecture Pattern

The recommended pattern separates the signed field generation (server) from form rendering (client) and webhook handling (API route):

Server Component — generate signed fields

// app/checkout/page.tsx
import { MyPOSClient } from 'mypos-online-checkout'
import { CheckoutPage } from './CheckoutPage'

const client = new MyPOSClient({ /* config */ })

export default async function Page({ searchParams }: { searchParams: { orderId: string } }) {
  const checkoutFields = await client.generateCheckoutFields({
    orderId: searchParams.orderId,
    amount: 19.99,
    currency: 'EUR',
    urlOk: 'https://mystore.example/checkout/success',
    urlCancel: 'https://mystore.example/checkout/cancel',
    urlNotify: 'https://mystore.example/api/payment/notify',
  })

  return <CheckoutPage checkoutFields={checkoutFields} checkoutUrl={client.checkoutUrl} />
}

Client Component — render form

// app/checkout/CheckoutPage.tsx
'use client'

import { PaymentForm } from 'mypos-online-checkout/react'

export function CheckoutPage({
  checkoutFields,
  checkoutUrl,
}: {
  checkoutFields: Record<string, string>
  checkoutUrl: string
}) {
  return (
    <div>
      <h2>Complete your payment</h2>
      <PaymentForm checkoutFields={checkoutFields} checkoutUrl={checkoutUrl} submitLabel="Pay €19.99" />
    </div>
  )
}

API Route — validate webhook

// app/api/payment/notify/route.ts
import { MyPOSClient, MyPOSSignatureError } from 'mypos-online-checkout'
import type { NextRequest } from 'next/server'

const client = new MyPOSClient({ /* config */ })

export async function POST(req: NextRequest) {
  const body = await req.text()
  const params = Object.fromEntries(new URLSearchParams(body))

  try {
    const result = await client.validateNotification(params)
    if (result.success) {
      // Update order status in DB
    }
  } catch (err) {
    if (err instanceof MyPOSSignatureError) {
      return new Response('Forbidden', { status: 403 })
    }
    throw err
  }

  return new Response('OK', { status: 200 })
}