diff options
Diffstat (limited to 'src/client/components/SyncStatusIndicator.tsx')
| -rw-r--r-- | src/client/components/SyncStatusIndicator.tsx | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/client/components/SyncStatusIndicator.tsx b/src/client/components/SyncStatusIndicator.tsx new file mode 100644 index 0000000..23e3ec6 --- /dev/null +++ b/src/client/components/SyncStatusIndicator.tsx @@ -0,0 +1,82 @@ +import { useSync } from "../stores"; +import { SyncStatus } from "../sync"; + +export function SyncStatusIndicator() { + const { isOnline, isSyncing, pendingCount, lastError, status } = useSync(); + + const getStatusText = (): string => { + if (!isOnline) { + return "Offline"; + } + if (isSyncing) { + return "Syncing..."; + } + if (status === SyncStatus.Error && lastError) { + return "Sync error"; + } + if (pendingCount > 0) { + return `${pendingCount} pending`; + } + return "Synced"; + }; + + const getStatusColor = (): string => { + if (!isOnline) { + return "#6c757d"; // gray + } + if (isSyncing) { + return "#007bff"; // blue + } + if (status === SyncStatus.Error) { + return "#dc3545"; // red + } + if (pendingCount > 0) { + return "#ffc107"; // yellow + } + return "#28a745"; // green + }; + + const getStatusIcon = (): string => { + if (!isOnline) { + return "\u25CB"; // hollow circle + } + if (isSyncing) { + return "\u21BB"; // rotating arrows + } + if (status === SyncStatus.Error) { + return "\u2717"; // cross mark + } + if (pendingCount > 0) { + return "\u25D4"; // partial circle + } + return "\u2713"; // check mark + }; + + return ( + <div + data-testid="sync-status-indicator" + style={{ + display: "inline-flex", + alignItems: "center", + gap: "0.25rem", + padding: "0.25rem 0.5rem", + borderRadius: "4px", + backgroundColor: "#f8f9fa", + border: "1px solid #dee2e6", + fontSize: "0.875rem", + }} + title={lastError || undefined} + > + <span + style={{ + color: getStatusColor(), + fontWeight: "bold", + }} + aria-hidden="true" + > + {getStatusIcon()} + </span> + <span style={{ color: getStatusColor() }}>{getStatusText()}</span> + </div> + ); +} |
