Sign in
<!-- DOCUMENTATION -->
Zentra Documentation
Everything you need to integrate, deploy, and master Zentra. Explore guides, API docs, and best practices for seamless printing from your web apps.
GET /api/labelsPOST /api/printWS /ws/print{}

Next.js WebSocket Integration Guide for PrintBridge Server (Windows)

This guide shows how to connect your Next.js webapp to the PrintBridge WebSocket server for automatic printer discovery and label printing.

Prerequisites

  • PrintBridge server running on localhost:8080
  • Next.js project set up
  • WebSocket support enabled
  1. 1. Create a WebSocket Hook (Recommended)

    Create file: hooks/usePrintBridge.ts
    import { useState, useEffect, useRef } from 'react';
    
    interface PrintBridgeMessage {
      type?: string;
      status?: string;
      message?: string;
      printers?: string[];
      defaultPrinter?: string;
      success?: boolean;
      printerName?: string;
      errorMessage?: string;
    }
    
    export const usePrintBridge = () => {
      const [isConnected, setIsConnected] = useState(false);
      const [printers, setPrinters] = useState<string[]>([]);
      const [defaultPrinter, setDefaultPrinter] = useState<string>('');
      const [lastPrintResult, setLastPrintResult] = useState<any>(null);
      const wsRef = useRef<WebSocket | null>(null);
      const reconnectTimeoutRef = useRef<NodeJS.Timeout>();
    
      const connect = () => {
        try {
          const ws = new WebSocket('ws://localhost:8080/ws');
          wsRef.current = ws;
    
          ws.onopen = () => {
            console.log('✅ Connected to PrintBridge server');
            setIsConnected(true);
          };
    
          ws.onmessage = (event) => {
            try {
              const data: PrintBridgeMessage = JSON.parse(event.data);
              console.log('📨 Received:', data);
    
              if (data.type === 'connection') {
                setPrinters(data.printers || []);
                setDefaultPrinter(data.defaultPrinter || '');
                console.log('🖨️ Printers discovered:', data.printers);
              }
    
              if (data.success !== undefined) {
                setLastPrintResult(data);
                console.log('🖨️ Print job result:', data);
              }
            } catch (error) {
              console.error('❌ Error parsing message:', error);
            }
          };
    
          ws.onclose = () => {
            console.log('🔌 Disconnected from PrintBridge');
            setIsConnected(false);
            setPrinters([]);
            setDefaultPrinter('');
            
            // Auto-reconnect after 3 seconds
            reconnectTimeoutRef.current = setTimeout(connect, 3000);
          };
    
          ws.onerror = (error) => {
            console.error('❌ WebSocket error:', error);
            setIsConnected(false);
          };
        } catch (error) {
          console.error('❌ Connection error:', error);
          setIsConnected(false);
        }
      };
    
      const disconnect = () => {
        if (reconnectTimeoutRef.current) {
          clearTimeout(reconnectTimeoutRef.current);
        }
        if (wsRef.current) {
          wsRef.current.close();
        }
      };
    
      const sendPrintJob = (base64Image: string, printerName?: string) => {
        if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
          console.log('🖨️ Sending print job...');
          wsRef.current.send(base64Image);
          return true;
        } else {
          console.error('❌ WebSocket not connected');
          return false;
        }
      };
    
      useEffect(() => {
        connect();
        return () => disconnect();
      }, []);
    
      return {
        isConnected,
        printers,
        defaultPrinter,
        lastPrintResult,
        sendPrintJob,
        connect,
        disconnect
      };
    };
  2. 2. Create a PrintBridge Provider (Context)

    Create file: contexts/PrintBridgeContext.tsx
    import React, { createContext, useContext, ReactNode } from 'react';
    import { usePrintBridge } from '../hooks/usePrintBridge';
    
    interface PrintBridgeContextType {
      isConnected: boolean;
      printers: string[];
      defaultPrinter: string;
      lastPrintResult: any;
      sendPrintJob: (base64Image: string, printerName?: string) => boolean;
    }
    
    const PrintBridgeContext = createContext<PrintBridgeContextType | undefined>(undefined);
    
    export const PrintBridgeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
      const printBridge = usePrintBridge();
    
      return (
        <PrintBridgeContext.Provider value={printBridge}>
          {children}
        </PrintBridgeContext.Provider>
      );
    };
    
    export const usePrintBridgeContext = () => {
      const context = useContext(PrintBridgeContext);
      if (context === undefined) {
        throw new Error('usePrintBridgeContext must be used within a PrintBridgeProvider');
      }
      return context;
    };
  3. 3. Wrap Your App with the Provider

    Update file: pages/_app.tsx (Pages Router) or app/layout.tsx (App Router)
    For Pages Router:
    import { PrintBridgeProvider } from '../contexts/PrintBridgeContext';
    
    function MyApp({ Component, pageProps }) {
      return (
        <PrintBridgeProvider>
          <Component {...pageProps} />
        </PrintBridgeProvider>
      );
    }
    
    export default MyApp;
    For App Router:
    import { PrintBridgeProvider } from '../contexts/PrintBridgeContext';
    
    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode
    }) {
      return (
        <html lang="en">
          <body>
            <PrintBridgeProvider>
              {children}
            </PrintBridgeProvider>
          </body>
        </html>
      );
    }
  4. 4. Create a Print Button Component

    Create file: components/PrintButton.tsx
    import { usePrintBridgeContext } from '../contexts/PrintBridgeContext';
    
    export const PrintButton: React.FC = () => {
      const { isConnected, printers, defaultPrinter, sendPrintJob } = usePrintBridgeContext();
    
      const handlePrint = async () => {
        // Convert your image to base64
        const base64Image = 'your-base64-image-string';
        
        if (sendPrintJob(base64Image, defaultPrinter)) {
          console.log('✅ Print job sent successfully');
        } else {
          console.error('❌ Failed to send print job');
        }
      };
    
      return (
        <div>
          <div>Status: {isConnected ? '🟢 Connected' : '🔴 Disconnected'}</div>
          <div>Available Printers: {printers.join(', ')}</div>
          <div>Default Printer: {defaultPrinter}</div>
          <button 
            onClick={handlePrint}
            disabled={!isConnected}
          >
            Print Label
          </button>
        </div>
      );
    };
  5. 5. Create a Connection Status Component

    Create file: components/ConnectionStatus.tsx
    import { usePrintBridgeContext } from '../contexts/PrintBridgeContext';
    
    export const ConnectionStatus = () => {
      const { isConnected, printers } = usePrintBridgeContext();
      return (
        <div className={"status " + (isConnected ? 'connected' : 'disconnected')}>
          <div>🖨️ PrintBridge: {isConnected ? "Connected" : "Disconnected"}</div>
          {isConnected && (
            <div>🖨️ Available Printers: {printers.length}</div>
          )}
        </div>
      );
    };
  6. 6. Add to Your Page

    Update file: pages/index.tsx (Pages Router) or app/page.tsx (App Router)
    import { ConnectionStatus } from '../components/ConnectionStatus';
    import { PrintButton } from '../components/PrintButton';
    
    export default function Home() {
      return (
        <div>
          <h1>My Label Printing App</h1>
          <ConnectionStatus />
          <PrintButton />
        </div>
      );
    }
  7. 7. Add CSS Styles (Optional)

    Add to your global CSS or component styles:
    .status {
      padding: 10px;
      border-radius: 4px;
      margin-bottom: 20px;
    }
    
    .status.connected {
      background: #d4edda;
      color: #155724;
      border: 1px solid #c3e6cb;
    }
    
    .status.disconnected {
      background: #f8d7da;
      color: #721c24;
      border: 1px solid #f5c6cb;
    }
    
    button {
      padding: 8px 16px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    
    button:hover {
      background: #0056b3;
    }
    
    button:disabled {
      background: #6c757d;
      cursor: not-allowed;
    }
  8. 8. Installation Steps

    1. Create the files above in your Next.js project structure
    2. Wrap your app with PrintBridgeProvider in _app.tsx or layout.tsx
    3. Use the hook in your components
    4. Start your PrintBridge server:
      cd PrintBridgeTrayApp
      dotnet run
    5. Start your Next.js app:
      npm run dev
  9. 9. Testing

    1. Open your Next.js app in the browser
    2. Open browser developer tools (F12)
    3. Check the console for connection logs
    4. You should see:
      • "✅ Connected to PrintBridge server"
      • "🖨️ Printers discovered: [printer list]"
    5. The connection status should show "Connected"
    6. Available printers should be displayed
  10. 10. Troubleshooting

    • Make sure PrintBridge server is running on localhost:8080
    • Check browser console for error messages
    • Verify WebSocket is supported in your browser
    • Check if firewall is blocking the connection
    • Try accessing http://localhost:8080 directly to verify server is up
  11. 11. Key Features

    • ✅ Auto-connect on app load
    • ✅ Auto-reconnect every 3 seconds if disconnected
    • ✅ Real-time printer discovery
    • ✅ Automatic default printer selection
    • ✅ Print job status updates
    • ✅ Error handling and logging
    • ✅ TypeScript support
    • ✅ React hooks integration
  12. 12. Usage Examples

    Basic usage in a component:
    import { usePrintBridgeContext } from '../contexts/PrintBridgeContext';
    
    export const MyComponent = () => {
      const { isConnected, printers, sendPrintJob } = usePrintBridgeContext();
      
      const printLabel = () => {
        const base64Image = 'your-image-base64-string';
        sendPrintJob(base64Image);
      };
      
      return (
        <div>
          <p>Connected: {isConnected ? 'Yes' : 'No'}</p>
          <p>Printers: {printers.join(', ')}</p>
          <button onClick={printLabel}>Print</button>
        </div>
      );
    };