FuturePayNG Logo
FuturePayNGv1.0.0
FuturePayNG Invoice Payment API v1.0.0

Web Checkout & Dynamic QR Code Integration

Complete guide to integrating the FuturePayNG dynamic QR code in your web application, featuring the complete production implementation for Next.js web checkouts.

web1. Web Checkout Architecture

How the Web Checkout Operates

The verified checkout flow operates entirely on the web without requiring any native mobile SDK. When a customer checks out, the web application executes the following sequence:

1Initiate Checkout

Web client submits cart items to POST /checkout, receiving payment.qr_code and expiration timestamp.

2Render Dynamic QR

Renders the base64 QR code inside the `#f8f7fc` modal with formatted expiration date and trust badges.

3Canvas jsQR Decode

Draws the QR image onto an offscreen HTML5 <canvas> to extract the URL and populate a clickable link.

43-Second Web Polling

Runs an automated 3-second interval polling /orders/status/:ref until status updates to paid.

Live Web Component Demo

Production Web QR Checkout Component

Directly replicates the UI, jsQR canvas decoding, and 3-second status polling in app/checkout/page.js.

FuturePayNG

Scan or Tap the QR to Pay

Scan with your FuturePayNG app or double-tap the QR code

EXPIRES:

06 Nov 2026, 11:15 AM

FuturePay Emblem
verified_user

Secure

Bank-grade
security

bolt

Instant

Payment in
seconds

lock

Private

Your data is
protected

gpp_goodProtected by bank-grade security.
futurepayng.com
Waiting for payment confirmation (poll #1)...
code3. Complete Next.js Frontend Implementation
app/checkout/page.js

Full Production Checkout Page Component

Below is the complete, self-contained Next.js App Router checkout page component powering a production e-commerce web checkout. It includes automated checkout initiation, client-side HTML5 canvas QR decoding with jsQR, 3-second status interval polling, the Web Share API with PNG download fallback, and the verified post-payment confirmation screen.

app/checkout/page.jsComplete Next.js Component
'use client';
import { useState, useEffect } from 'react';
import { api } from '@/lib/api';
import { useAuthStore } from '@/lib/store/authStore';
import styles from './page.module.css';
import jsQR from 'jsqr';

export default function Checkout() {
  const { isAuthenticated, user } = useAuthStore();
  const [shippingMethod, setShippingMethod] = useState('standard');
  const [cartItems, setCartItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [submitting, setSubmitting] = useState(false);
  const [paymentData, setPaymentData] = useState(null);
  const [showAuthPopup, setShowAuthPopup] = useState(false);
  const [authForm, setAuthForm] = useState({ name: '', email: '', password: '', phone: '' });
  const [authError, setAuthError] = useState('');

  const [orderReference, setOrderReference] = useState(null);
  const [paymentStatus, setPaymentStatus] = useState('pending');
  const [qrCodeUrl, setQrCodeUrl] = useState('');





  useEffect(() => {
    if (paymentData && paymentData.qr_code) {
      const img = new Image();
      img.onload = () => {
        const canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        try {
          const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
          const code = jsQR(imageData.data, imageData.width, imageData.height);
          if (code && code.data) {
            setQrCodeUrl(code.data);
          }
        } catch (e) {
          console.error("Failed to decode QR code:", e);
        }
      };
      img.src = paymentData.qr_code;
    }
  }, [paymentData]);

  useEffect(() => {
    async function loadCart() {
      try {
        const res = await api.get('/cart');
        const items = res.items || [];
        setCartItems(items);
        if (items.length > 0) {
          handleCheckoutAuto(items);
        } else {
          setLoading(false);
        }
      } catch (err) {
        console.error(err);
        setLoading(false);
      }
    }
    loadCart();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    let interval;
    if (orderReference && paymentStatus === 'pending') {
      interval = setInterval(async () => {
        try {
          const res = await api.get(`/orders/status/${orderReference}`);
          if (res.status === 'paid') {
            setPaymentStatus('paid');
            clearInterval(interval);
          }
        } catch (e) {
          // ignore
        }
      }, 3000);
    }
    return () => clearInterval(interval);
  }, [orderReference, paymentStatus]);

  const handleAuthSubmit = async (e) => {
    e.preventDefault();
    setAuthError('');
    setSubmitting(true);
    try {
      // Basic register, assuming the endpoint exists
      const res = await api.post('/auth/register', authForm);
      if (res.token) {
        useAuthStore.getState().login(res.user, res.token);
        setShowAuthPopup(false);
        // Retry checkout
        setTimeout(() => handleCheckoutAuto(cartItems), 500);
      }
    } catch (err) {
      setAuthError(err.message || 'Signup failed');
      setSubmitting(false);
    }
  };


  const handleCheckoutAuto = async (itemsToCheckout) => {
    setSubmitting(true);
    try {
      const items = itemsToCheckout.map(item => ({
        product_id: item.product_id,
        qty: item.qty,
      }));

      const res = await api.post('/checkout', {
        items,
        email: user?.email || 'guest@example.com',
        phone: user?.phone || '0000000000',
        country_code: 'NG',
        region: 'N/A',
        shipping_method: 'standard',
        shipping_address: {
          fullName: user?.name || 'Guest User',
          email: user?.email || 'guest@example.com',
          phoneNumber: user?.phone || '0000000000',
          streetAddress: 'N/A',
          city: 'N/A',
          state: 'N/A'
        }
      });

      if (res.payment && res.payment.qr_code) {
        setPaymentData(res.payment);
        setOrderReference(res.order_reference);
      } else {
        alert('Payment gateway error. Please try again.');
      }
    } catch (err) {
      console.error(err);
      alert('Checkout failed: ' + (err.message || 'Unknown error'));
    } finally {
      setSubmitting(false);
      setLoading(false);
    }
  };

  if (loading || submitting) {
    return (
      <div className={styles.main} style={{textAlign: 'center', padding: '60px 20px', display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
        <span className="material-symbols-outlined" style={{fontSize: '48px', color: 'var(--primary)', animation: 'spin 2s linear infinite'}}>refresh</span>
        <h3 className="font-headline-md" style={{marginTop: '20px', marginBottom: '8px'}}>Generating your FuturePay QR Code...</h3>
        <p className="font-body-md" style={{color: 'var(--on-surface-variant)'}}>Please wait while we secure your payment session.</p>
        <style dangerouslySetInnerHTML={{__html: `
          @keyframes spin { 100% { transform: rotate(360deg); } }
        `}} />
      </div>
    );
  }

  if (paymentStatus === 'paid') {
    return (
      <div className={styles.main} style={{textAlign: 'center', padding: '60px 20px', display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
        <span className="material-symbols-outlined" style={{fontSize: '80px', color: '#10B981', marginBottom: '20px'}}>check_circle</span>
        <h2 className="font-headline-xl" style={{marginBottom: '16px'}}>Payment Successful!</h2>
        
        <div style={{ background: '#f8fafc', padding: '24px', borderRadius: '12px', border: '1px solid #e2e8f0', maxWidth: '500px', width: '100%', marginBottom: '24px' }}>
          <p className="font-body-lg" style={{ marginBottom: '16px' }}>Your order has been confirmed.</p>
          <p className="font-title-lg" style={{ fontSize: '24px', fontWeight: 'bold', color: 'var(--primary)', letterSpacing: '2px', marginBottom: '16px' }}>
            {orderReference}
          </p>
          <p className="font-body-md" style={{ color: '#475569', fontSize: '14px' }}>
            <strong>Important:</strong> Please save this Order Reference. Since you checked out as a guest, you will need this exact reference number to track your shipping status.
          </p>
        </div>
        
        <div style={{ display: 'flex', gap: '16px' }}>
          <button 
            onClick={() => window.location.href = '/track'}
            style={{ padding: '14px 24px', background: 'var(--primary)', color: '#fff', border: 'none', borderRadius: '8px', cursor: 'pointer', fontWeight: 'bold', fontSize: '15px' }}
          >
            Track Order Status
          </button>
          <button 
            onClick={() => window.location.href = '/catalog'}
            style={{ padding: '14px 24px', background: 'transparent', color: 'var(--primary)', border: '1px solid var(--primary)', borderRadius: '8px', cursor: 'pointer', fontWeight: 'bold', fontSize: '15px' }}
          >
            Continue Shopping
          </button>
        </div>
      </div>
    );
  }

  if (paymentData) {
    return (
      <div style={{
        backgroundColor: '#f8f7fc',
        minHeight: '100vh',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        padding: '40px 20px',
        fontFamily: 'var(--font-sans, system-ui, sans-serif)',
        width: '100%'
      }}>
        {/* Logo */}
        <div style={{ display: 'flex', alignItems: 'center', gap: '6px', marginBottom: '32px' }}>
          <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <rect x="5" y="3" width="14" height="4" rx="2" fill="#F49A25"/>
            <path d="M5 10C5 8.89543 5.89543 8 7 8H14C15.1046 8 16 8.89543 16 10C16 11.1046 15.1046 12 14 12H9V20C9 21.1046 8.10457 22 7 22C5.89543 22 5 21.1046 5 20V10Z" fill="#1C4ED8"/>
          </svg>
          <span style={{ fontSize: '20px', fontWeight: '800', color: '#190d3e', letterSpacing: '-0.3px' }}>
            FuturePay<span style={{ color: '#F49A25' }}>NG</span>
          </span>
        </div>

        {/* Title */}
        <h2 style={{ fontSize: '26px', fontWeight: '800', color: '#190d3e', textAlign: 'center', marginBottom: '8px', maxWidth: '320px', lineHeight: '1.2' }}>
          Scan or Tap the QR to Pay
        </h2>
        <p style={{ fontSize: '14px', color: '#6b6685', textAlign: 'center', marginBottom: '24px' }}>
          Scan with your FuturePayNG app or double-tap the QR code
        </p>

        {/* Expires Box */}
        {paymentData.expires_at && (
          <div style={{ 
            backgroundColor: '#efedf9', 
            border: '1px solid #dedcef', 
            borderRadius: '12px', 
            padding: '12px 24px', 
            width: '100%', 
            maxWidth: '340px', 
            textAlign: 'center',
            marginBottom: '24px'
          }}>
            <p style={{ fontSize: '11px', fontWeight: '700', color: '#6b6685', letterSpacing: '1px', marginBottom: '4px' }}>EXPIRES:</p>
            <p style={{ fontSize: '15px', fontWeight: '800', color: '#190d3e' }}>
              {(() => {
                const date = new Date(paymentData.expires_at);
                const day = date.getDate().toString().padStart(2, '0');
                const month = date.toLocaleString('en-GB', { month: 'short' });
                const year = date.getFullYear();
                const time = date.toLocaleString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true });
                return `${day} ${month} ${year}, ${time}`;
              })()}
            </p>
          </div>
        )}

        {/* QR Code Container */}
        <div style={{ 
          backgroundColor: '#ffffff', 
          borderRadius: '16px', 
          padding: '24px', 
          width: '100%', 
          maxWidth: '340px', 
          border: '1px solid #dedcef',
          marginBottom: '24px',
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center'
        }}>
          <a href={qrCodeUrl || paymentData.checkout_url || `futurepay://checkout?invoice=${paymentData.invoice_reference}`} target="_blank" rel="noopener noreferrer">
            <img src={paymentData.qr_code} alt="FuturePay QR Code" style={{ width: '100%', maxWidth: '250px', height: 'auto', display: 'block' }} />
          </a>
        </div>

        {/* Share Button */}
        <button 
          onClick={async () => {
            try {
              const fetchRes = await fetch(paymentData.qr_code);
              const blob = await fetchRes.blob();
              const file = new File([blob], 'futurepay-qr.png', { type: 'image/png' });

              if (navigator.canShare && navigator.canShare({ files: [file] })) {
                await navigator.share({
                  title: 'FuturePay QR Code',
                  text: 'Scan to pay this FuturePay invoice',
                  files: [file]
                });
              } else {
                // Fallback to download if sharing file is not supported
                const link = document.createElement('a');
                link.href = paymentData.qr_code;
                link.download = 'futurepay-qr.png';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
              }
            } catch (error) {
              console.error('Error sharing or downloading QR code:', error);
              // Fallback to basic share if file sharing fails
              if (navigator.share) {
                navigator.share({
                  title: 'FuturePay QR Code',
                  text: 'Scan to pay',
                  url: paymentData.qr_code
                }).catch(console.error);
              } else {
                // Final fallback to download
                const link = document.createElement('a');
                link.href = paymentData.qr_code;
                link.download = 'futurepay-qr.png';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
              }
            }
          }} 
          className={styles.shareButton}
        >
          Share QR Code <span className="material-symbols-outlined" style={{fontSize: '18px'}}>share</span>
        </button>

        {/* Features Box */}
        <div style={{ 
          backgroundColor: '#efedf9', 
          border: '1px solid #dedcef', 
          borderRadius: '16px', 
          padding: '20px 12px', 
          width: '100%', 
          maxWidth: '340px', 
          display: 'flex',
          justifyContent: 'space-between',
          marginBottom: '16px'
        }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1, borderRight: '1px solid #dedcef' }}>
            <div style={{ width: '36px', height: '36px', borderRadius: '50%', backgroundColor: '#ffffff', display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '12px', color: '#190d3e' }}>
              <span className="material-symbols-outlined" style={{fontSize: '18px'}}>verified_user</span>
            </div>
            <p style={{ fontSize: '13px', fontWeight: '800', color: '#190d3e', marginBottom: '4px' }}>Secure</p>
            <p style={{ fontSize: '11px', color: '#6b6685', textAlign: 'center', padding: '0 4px', lineHeight: '1.4' }}>Bank-grade<br/>security</p>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1, borderRight: '1px solid #dedcef' }}>
            <div style={{ width: '36px', height: '36px', borderRadius: '50%', backgroundColor: '#ffffff', display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '12px', color: '#190d3e' }}>
              <span className="material-symbols-outlined" style={{fontSize: '18px'}}>bolt</span>
            </div>
            <p style={{ fontSize: '13px', fontWeight: '800', color: '#190d3e', marginBottom: '4px' }}>Instant</p>
            <p style={{ fontSize: '11px', color: '#6b6685', textAlign: 'center', padding: '0 4px', lineHeight: '1.4' }}>Payment in<br/>seconds</p>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1 }}>
            <div style={{ width: '36px', height: '36px', borderRadius: '50%', backgroundColor: '#ffffff', display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '12px', color: '#190d3e' }}>
              <span className="material-symbols-outlined" style={{fontSize: '18px'}}>lock</span>
            </div>
            <p style={{ fontSize: '13px', fontWeight: '800', color: '#190d3e', marginBottom: '4px' }}>Private</p>
            <p style={{ fontSize: '11px', color: '#6b6685', textAlign: 'center', padding: '0 4px', lineHeight: '1.4' }}>Your data is<br/>protected</p>
          </div>
        </div>

        {/* Footer Box */}
        <div style={{ 
          backgroundColor: '#efedf9', 
          border: '1px solid #dedcef', 
          borderRadius: '12px', 
          padding: '16px', 
          width: '100%', 
          maxWidth: '340px', 
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center'
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
            <span className="material-symbols-outlined" style={{fontSize: '18px', color: '#6b6685'}}>gpp_good</span>
            <p style={{ fontSize: '11px', color: '#6b6685', lineHeight: '1.4', maxWidth: '120px' }}>Your payment is protected by bank-grade security.</p>
          </div>
          <p style={{ fontSize: '12px', fontWeight: '800', color: '#190d3e' }}>futurepayng.com</p>
        </div>

        <p className="font-body-sm" style={{marginTop: '24px', color: '#6b6685', fontSize: '13px'}}>Waiting for payment confirmation...</p>
      </div>
    );
  }

  return (
    <div className={styles.main}>
      <div style={{padding: '40px', textAlign: 'center'}}>
        <h3>Your cart is empty</h3>
        <p>Please add items to your cart before checking out.</p>
      </div>
    </div>
  );
}
lightbulb
Copy & Integrate into your Next.js App:Ensure you have installed npm install jsqr in your Next.js project. You can copy the code above directly into your App Router route (e.g. app/checkout/page.js) and adapt the cart loading and API endpoints to your backend.
qr_code_24. Dynamic QR Code Display & Expiration Box

Modal Markup & Expiration Date Formatting

The verified checkout renders the QR code with an expiration banner styled in #efedf9. The date formatter converts the ISO-8601 string into a clear date and time display:

app/checkout/page.jsNext.js JSX
{/* Formatted Expiration Banner */}
{paymentData.expires_at && (
  <div style={{ 
    backgroundColor: '#efedf9', 
    border: '1px solid #dedcef', 
    borderRadius: '12px', 
    padding: '12px 24px', 
    width: '100%', 
    maxWidth: '340px', 
    textAlign: 'center',
    marginBottom: '24px'
  }}>
    <p style={{ fontSize: '11px', fontWeight: '700', color: '#6b6685', letterSpacing: '1px', marginBottom: '4px' }}>
      EXPIRES:
    </p>
    <p style={{ fontSize: '15px', fontWeight: '800', color: '#190d3e' }}>
      {(() => {
        const date = new Date(paymentData.expires_at);
        const day = date.getDate().toString().padStart(2, '0');
        const month = date.toLocaleString('en-GB', { month: 'short' });
        const year = date.getFullYear();
        const time = date.toLocaleString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true });
        return `${day} ${month} ${year}, ${time}`;
      })()}
    </p>
  </div>
)}

{/* QR Code Container */}
<div style={{ 
  backgroundColor: '#ffffff', 
  borderRadius: '16px', 
  padding: '24px', 
  width: '100%', 
  maxWidth: '340px', 
  border: '1px solid #dedcef',
  marginBottom: '24px',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center'
}}>
  <a 
    href={qrCodeUrl || paymentData.checkout_url || `https://stage-futurepay.yellow.team/checkout/${paymentData.invoice_reference}`} 
    target="_blank" 
    rel="noopener noreferrer"
  >
    <img 
      src={paymentData.qr_code} 
      alt="FuturePay QR Code" 
      style={{ width: '100%', maxWidth: '250px', height: 'auto', display: 'block' }} 
    />
  </a>
</div>
qr_code_scanner5. Client-Side jsQR Canvas Decoding

Decoding the QR Payload in the Web Browser

Rather than making an extra server round-trip, the web client loads the base64 image onto an in-memory HTML5 <canvas> element and passes the raw pixel buffer to jsQR:

app/checkout/page.jsClient Hook
import jsQR from 'jsqr';

useEffect(() => {
  if (paymentData && paymentData.qr_code) {
    const img = new Image();
    img.onload = () => {
      // 1. Create offscreen canvas matching image dimensions
      const canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;
      const ctx = canvas.getContext("2d");
      
      // 2. Draw base64 image onto canvas context
      ctx.drawImage(img, 0, 0);
      try {
        // 3. Extract raw RGBA pixel data
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        
        // 4. Decode QR code with jsQR
        const code = jsQR(imageData.data, imageData.width, imageData.height);
        if (code && code.data) {
          setQrCodeUrl(code.data);
        }
      } catch (e) {
        console.error("Failed to decode QR code:", e);
      }
    };
    img.src = paymentData.qr_code;
  }
}, [paymentData]);
sync6. Real-Time Web Status Polling

Automated 3-Second Status Interval

While the QR modal is displayed, an active React useEffect interval queries the order status every 3,000 milliseconds. When the status changes to paid, the interval is cleared and the UI immediately transitions to the order confirmation view:

app/checkout/page.jsPolling Hook
useEffect(() => {
  let interval;
  if (orderReference && paymentStatus === 'pending') {
    interval = setInterval(async () => {
      try {
        const res = await api.get(`/orders/status/${orderReference}`);
        if (res.status === 'paid') {
          setPaymentStatus('paid');
          clearInterval(interval);
        }
      } catch (e) {
        // Ignore temporary network glitches and continue polling
      }
    }, 3000);
  }
  return () => clearInterval(interval);
}, [orderReference, paymentStatus]);
share7. Web Share API & Browser File Download

Sharing or Saving the QR Code on Web Browsers

The "Share QR Code" button fetches the base64 string, converts it to a standard PNG File object, and attempts to invoke navigator.share(). If file sharing is unsupported, it automatically falls back to an anchor download:

app/checkout/page.jsWeb Share Handler
<button 
  onClick={async () => {
    try {
      const fetchRes = await fetch(paymentData.qr_code);
      const blob = await fetchRes.blob();
      const file = new File([blob], 'futurepay-qr.png', { type: 'image/png' });

      if (navigator.canShare && navigator.canShare({ files: [file] })) {
        await navigator.share({
          title: 'FuturePay QR Code',
          text: 'Scan to pay this FuturePayNG invoice',
          files: [file]
        });
      } else {
        // Fallback: direct browser file download
        const link = document.createElement('a');
        link.href = paymentData.qr_code;
        link.download = 'futurepay-qr.png';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }
    } catch (error) {
      console.error('Error sharing or downloading QR code:', error);
      // Fallback to basic link download
      const link = document.createElement('a');
      link.href = paymentData.qr_code;
      link.download = 'futurepay-qr.png';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  }} 
  className={styles.shareButton}
>
  Share QR Code <span className="material-symbols-outlined" style={{fontSize: '18px'}}>share</span>
</button>
check_circle8. Order Confirmation Screen

Post-Payment Success Screen

When the polling interval receives status: 'paid', the checkout renders the confirmation card with the order reference:

app/checkout/page.jsSuccess View
if (paymentStatus === 'paid') {
  return (
    <div style={{ textAlign: 'center', padding: '60px 20px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
      <span className="material-symbols-outlined" style={{ fontSize: '80px', color: '#10B981', marginBottom: '20px' }}>
        check_circle
      </span>
      <h2 style={{ fontSize: '28px', fontWeight: '800', marginBottom: '16px', color: '#0F172A' }}>
        Payment Successful!
      </h2>
      
      <div style={{ background: '#f8fafc', padding: '24px', borderRadius: '12px', border: '1px solid #e2e8f0', maxWidth: '500px', width: '100%', marginBottom: '24px' }}>
        <p style={{ marginBottom: '16px', color: '#334155', fontSize: '15px' }}>
          Your order has been confirmed.
        </p>
        <p style={{ fontSize: '24px', fontWeight: 'bold', color: '#0e53c8', letterSpacing: '2px', marginBottom: '16px' }}>
          {orderReference}
        </p>
        <p style={{ color: '#475569', fontSize: '14px' }}>
          <strong>Important:</strong> Please save this Order Reference. Since you checked out as a guest, you will need this exact reference number to track your shipping status.
        </p>
      </div>
      
      <div style={{ display: 'flex', gap: '16px' }}>
        <button onClick={() => window.location.href = '/track'} style={{ padding: '14px 24px', background: '#0e53c8', color: '#fff', border: 'none', borderRadius: '8px', cursor: 'pointer', fontWeight: 'bold' }}>
          Track Order Status
        </button>
        <button onClick={() => window.location.href = '/catalog'} style={{ padding: '14px 24px', background: 'transparent', color: '#0e53c8', border: '1px solid #0e53c8', borderRadius: '8px', cursor: 'pointer', fontWeight: 'bold' }}>
          Continue Shopping
        </button>
      </div>
    </div>
  );
}