import React, { useState, useMemo } from 'react'; import { useSource, useAppState, useAction } from './sdk'; import { Badge, Metric, Glass, Icon } from './components'; import { BarChart, Bar, LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { TrendingUp, DollarSign, RefreshCw, AlertCircle, CheckCircle, Clock, Package, FileText, ArrowRightLeft, Shield, Zap } from 'lucide-react'; // Mock data for when no live data is available const MOCK_SYNC_OPERATIONS = [ { id: 'sync-001', timestamp: '2024-01-15T10:30:00Z', type: 'Order Sync', status: 'completed', shopifyId: 'ORD-1001', qbId: 'INV-5001', amount: 1250.00, items: 3, duration: 2.3 }, { id: 'sync-002', timestamp: '2024-01-15T11:15:00Z', type: 'Product Sync', status: 'completed', shopifyId: 'PRD-2001', qbId: 'ITEM-3001', amount: 0, items: 1, duration: 1.1 }, { id: 'sync-003', timestamp: '2024-01-15T12:00:00Z', type: 'Order Sync', status: 'failed', shopifyId: 'ORD-1002', qbId: null, amount: 890.50, items: 2, duration: 0.5, error: 'Customer not found in QuickBooks' }, { id: 'sync-004', timestamp: '2024-01-15T13:45:00Z', type: 'Inventory Sync', status: 'completed', shopifyId: 'INV-3001', qbId: 'ADJ-4001', amount: 0, items: 15, duration: 3.2 }, { id: 'sync-005', timestamp: '2024-01-15T14:20:00Z', type: 'Order Sync', status: 'pending', shopifyId: 'ORD-1003', qbId: null, amount: 2100.00, items: 5, duration: 0 }, { id: 'sync-006', timestamp: '2024-01-15T15:00:00Z', type: 'Refund Sync', status: 'completed', shopifyId: 'REF-4001', qbId: 'CR-6001', amount: -350.00, items: 1, duration: 1.8 }, { id: 'sync-007', timestamp: '2024-01-15T15:30:00Z', type: 'Order Sync', status: 'completed', shopifyId: 'ORD-1004', qbId: 'INV-5002', amount: 675.25, items: 2, duration: 1.5 }, { id: 'sync-008', timestamp: '2024-01-15T16:10:00Z', type: 'Product Sync', status: 'warning', shopifyId: 'PRD-2002', qbId: 'ITEM-3002', amount: 0, items: 1, duration: 4.5, error: 'Price mismatch detected' }, ]; const MOCK_CHART_DATA = [ { time: '09:00', orders: 12, products: 5, inventory: 3 }, { time: '10:00', orders: 18, products: 8, inventory: 6 }, { time: '11:00', orders: 25, products: 12, inventory: 9 }, { time: '12:00', orders: 22, products: 10, inventory: 7 }, { time: '13:00', orders: 30, products: 15, inventory: 11 }, { time: '14:00', orders: 28, products: 14, inventory: 10 }, { time: '15:00', orders: 35, products: 18, inventory: 14 }, { time: '16:00', orders: 32, products: 16, inventory: 12 }, ]; const STATUS_COLORS = { completed: '#10b981', failed: '#ef4444', pending: '#f59e0b', warning: '#f59e0b', }; const COLORS = ['#8b5cf6', '#06b6d4', '#10b981', '#f59e0b', '#ef4444']; export default function App() { const [activeTab, setActiveTab] = useState('overview'); const [selectedSync, setSelectedSync] = useState(null); const [filterStatus, setFilterStatus] = useState('all'); const { data, loading, error, refetch } = useSource('/api/framework/connections/app/shopify-quickbooks-sync/data', 30000); const dispatch = useAction(); // Use live data if available, otherwise use mock data const syncOperations = useMemo(() => { const liveData = data?.providers?.shopify?.data || data?.providers?.quickbooks?.data; if (liveData && Array.isArray(liveData) && liveData.length > 0) { return liveData; } return MOCK_SYNC_OPERATIONS; }, [data]); const filteredOperations = useMemo(() => { if (filterStatus === 'all') return syncOperations; return syncOperations.filter((op: any) => op.status === filterStatus); }, [syncOperations, filterStatus]); // Calculate KPIs const kpis = useMemo(() => { const total = syncOperations.length; const completed = syncOperations.filter((op: any) => op.status === 'completed').length; const failed = syncOperations.filter((op: any) => op.status === 'failed').length; const pending = syncOperations.filter((op: any) => op.status === 'pending').length; const successRate = total > 0 ? Math.round((completed / total) * 100) : 0; const totalValue = syncOperations.reduce((sum: number, op: any) => sum + Math.abs(op.amount || 0), 0); const avgDuration = syncOperations.filter((op: any) => op.duration > 0).reduce((sum: number, op: any) => sum + op.duration, 0) / Math.max(1, syncOperations.filter((op: any) => op.duration > 0).length); return { total, completed, failed, pending, successRate, totalValue, avgDuration: avgDuration.toFixed(1) }; }, [syncOperations]); const statusDistribution = useMemo(() => { return [ { name: 'Completed', value: kpis.completed, color: STATUS_COLORS.completed }, { name: 'Failed', value: kpis.failed, color: STATUS_COLORS.failed }, { name: 'Pending', value: kpis.pending, color: STATUS_COLORS.pending }, { name: 'Warning', value: syncOperations.filter((op: any) => op.status === 'warning').length, color: STATUS_COLORS.warning }, ].filter(s => s.value > 0); }, [kpis, syncOperations]); const getStatusBadge = (status: string) => { const variants: Record = { completed: { variant: 'positive' as const, icon: 'check' }, failed: { variant: 'negative' as const, icon: 'alert' }, pending: { variant: 'neutral' as const, icon: 'clock' }, warning: { variant: 'neutral' as const, icon: 'alert' }, }; const config = variants[status] || variants.pending; return ; }; const handleConnectProvider = (provider: string) => { dispatch('oauth', { service: provider }); }; // Loading state if (loading && !syncOperations.length) { return (
); } return (
{/* Header */}

Shopify-QuickBooks Sync Dashboard

Real-time synchronization monitoring

{/* Tabs */}
{['overview', 'operations', 'analytics', 'settings'].map(tab => ( ))}
{/* Connection Status Banner */} {error && (

Live data unavailable. Showing demo data.

Connect Shopify and QuickBooks to see real sync operations.

)} {/* KPI Cards */}
Total Syncs
{kpis.total}
Last 24 hours
Success Rate
{kpis.successRate}%
{kpis.completed} completed
Total Value
${kpis.totalValue.toLocaleString()}
Synced transactions
Avg Duration
{kpis.avgDuration}s
Per sync operation
{/* Overview Tab */} {activeTab === 'overview' && ( <> {/* Charts Row */}

Sync Activity Over Time

Status Distribution

`${name} ${(percent * 100).toFixed(0)}%`} labelLine={false} > {statusDistribution.map((entry, index) => ( ))}
{/* Recent Operations Table */}

Recent Sync Operations

{['all', 'completed', 'failed', 'pending'].map(status => ( ))}
{filteredOperations.slice(0, 10).map((op: any) => ( setSelectedSync(op)} > ))}
Type Status Shopify ID QB ID Amount Duration Time
{op.type}
{getStatusBadge(op.status)} {op.shopifyId} {op.qbId || '-'} = 0 ? 'text-emerald-400' : 'text-red-400'}> {op.amount >= 0 ? '+' : ''}${Math.abs(op.amount).toFixed(2)} {op.duration > 0 ? `${op.duration}s` : '-'} {new Date(op.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
)} {/* Operations Tab */} {activeTab === 'operations' && (

All Sync Operations

{filteredOperations.map((op: any) => (
setSelectedSync(op)} >
{op.type} {getStatusBadge(op.status)}
{op.shopifyId} → {op.qbId || 'Pending'}
{op.amount >= 0 ? '+' : ''}${Math.abs(op.amount).toFixed(2)}
{new Date(op.timestamp).toLocaleString()}
{op.error && (
{op.error}
)}
))}
)} {/* Analytics Tab */} {activeTab === 'analytics' && (

Sync Volume by Type

o.type.includes('Order')).length }, { name: 'Products', count: syncOperations.filter((o: any) => o.type.includes('Product')).length }, { name: 'Inventory', count: syncOperations.filter((o: any) => o.type.includes('Inventory')).length }, { name: 'Refunds', count: syncOperations.filter((o: any) => o.type.includes('Refund')).length }, ]}>

Performance Metrics

Average Sync Duration {kpis.avgDuration}s
Success Rate {kpis.successRate}%
Failed Syncs {kpis.failed}
)} {/* Settings Tab */} {activeTab === 'settings' && (

Integration Settings

Shopify
E-commerce platform
QuickBooks
Accounting software
)}
{/* Detail Modal */} {selectedSync && (
setSelectedSync(null)} > e.stopPropagation()} >

Sync Operation Details

Type
{selectedSync.type}
Status
{getStatusBadge(selectedSync.status)}
Shopify ID
{selectedSync.shopifyId}
QuickBooks ID
{selectedSync.qbId || 'Pending'}
Amount
= 0 ? 'text-emerald-400' : 'text-red-400'}`}> {selectedSync.amount >= 0 ? '+' : ''}${Math.abs(selectedSync.amount).toFixed(2)}
Duration
{selectedSync.duration > 0 ? `${selectedSync.duration}s` : 'Pending'}
Items Synced
{selectedSync.items}
Timestamp
{new Date(selectedSync.timestamp).toLocaleString()}
{selectedSync.error && (
Error Details
{selectedSync.error}
)}
Raw Data
                  {JSON.stringify(selectedSync, null, 2)}
                
)}
); } // Missing icon imports import { Settings, Activity, BarChart3 } from 'lucide-react';