feat: integrate sync status indicator into highlights panel
- Updated HighlightsTab to accept syncStatus and syncErrorMessage props - Added SyncStatusIndicator component import and display in highlights panel - Enhanced BibleReaderApp with sync status tracking state (synced/syncing/pending/error) - Modified performSync function to update sync status based on result - Updated VersDetailsPanel to pass sync status props through to HighlightsTab - Sync status now visible to users in the Highlights tab with real-time updates Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,8 @@ export function BibleReaderApp() {
|
||||
const [booksLoading, setBooksLoading] = useState(true)
|
||||
const [highlights, setHighlights] = useState<Map<string, BibleHighlight>>(new Map())
|
||||
const syncManager = useRef<HighlightSyncManager | null>(null)
|
||||
const [syncStatus, setSyncStatus] = useState<'synced' | 'syncing' | 'pending' | 'error'>('synced')
|
||||
const [syncError, setSyncError] = useState<string | null>(null)
|
||||
|
||||
// Load books on mount or when locale changes
|
||||
useEffect(() => {
|
||||
@@ -281,17 +283,19 @@ export function BibleReaderApp() {
|
||||
if (!syncManager.current) return
|
||||
|
||||
try {
|
||||
const pending = await syncManager.current.getPendingSyncItems()
|
||||
if (pending.length === 0) return
|
||||
setSyncStatus('syncing')
|
||||
const result = await syncManager.current.performSync()
|
||||
|
||||
await syncManager.current.markSyncing(pending.map(h => h.id))
|
||||
|
||||
// TODO: POST to /api/highlights/bulk in Phase 2.1B
|
||||
|
||||
await syncManager.current.markSynced(pending.map(h => h.id))
|
||||
if (result.errors > 0) {
|
||||
setSyncStatus('error')
|
||||
setSyncError(`Failed to sync ${result.errors} highlights`)
|
||||
} else {
|
||||
setSyncStatus('synced')
|
||||
setSyncError(null)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Sync failed:', error)
|
||||
// Mark items with error status
|
||||
setSyncStatus('error')
|
||||
setSyncError(error instanceof Error ? error.message : 'Unknown error')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +374,8 @@ export function BibleReaderApp() {
|
||||
onHighlightVerse={handleHighlightVerse}
|
||||
onChangeHighlightColor={handleChangeHighlightColor}
|
||||
onRemoveHighlight={handleRemoveHighlight}
|
||||
syncStatus={syncStatus}
|
||||
syncErrorMessage={syncError || undefined}
|
||||
/>
|
||||
|
||||
{/* Settings panel */}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
import { Box, Button, Typography, Divider } from '@mui/material'
|
||||
import { BibleVerse, HighlightColor } from '@/types'
|
||||
import { SyncStatusIndicator } from './sync-status-indicator'
|
||||
|
||||
const HIGHLIGHT_COLORS: HighlightColor[] = ['yellow', 'orange', 'pink', 'blue']
|
||||
|
||||
@@ -17,6 +18,8 @@ interface HighlightsTabProps {
|
||||
currentColor: HighlightColor | null
|
||||
onToggleHighlight: () => void
|
||||
onColorChange: (color: HighlightColor) => void
|
||||
syncStatus?: 'synced' | 'syncing' | 'pending' | 'error'
|
||||
syncErrorMessage?: string
|
||||
}
|
||||
|
||||
export function HighlightsTab({
|
||||
@@ -24,7 +27,9 @@ export function HighlightsTab({
|
||||
isHighlighted,
|
||||
currentColor,
|
||||
onToggleHighlight,
|
||||
onColorChange
|
||||
onColorChange,
|
||||
syncStatus,
|
||||
syncErrorMessage
|
||||
}: HighlightsTabProps) {
|
||||
if (!verse) return null
|
||||
|
||||
@@ -80,6 +85,18 @@ export function HighlightsTab({
|
||||
|
||||
<Divider sx={{ my: 2 }} />
|
||||
|
||||
{syncStatus && (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="subtitle2" sx={{ mb: 1 }}>
|
||||
Sync Status
|
||||
</Typography>
|
||||
<SyncStatusIndicator
|
||||
status={syncStatus}
|
||||
errorMessage={syncErrorMessage}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
You can highlight the same verse multiple times with different colors.
|
||||
</Typography>
|
||||
|
||||
@@ -17,6 +17,8 @@ interface VersDetailsPanelProps {
|
||||
onHighlightVerse?: (color: HighlightColor) => void
|
||||
onChangeHighlightColor?: (color: HighlightColor) => void
|
||||
onRemoveHighlight?: () => void
|
||||
syncStatus?: 'synced' | 'syncing' | 'pending' | 'error'
|
||||
syncErrorMessage?: string
|
||||
}
|
||||
|
||||
export function VersDetailsPanel({
|
||||
@@ -31,6 +33,8 @@ export function VersDetailsPanel({
|
||||
onHighlightVerse,
|
||||
onChangeHighlightColor,
|
||||
onRemoveHighlight,
|
||||
syncStatus,
|
||||
syncErrorMessage,
|
||||
}: VersDetailsPanelProps) {
|
||||
const theme = useTheme()
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
|
||||
@@ -141,6 +145,8 @@ export function VersDetailsPanel({
|
||||
}
|
||||
}}
|
||||
onColorChange={(color) => onChangeHighlightColor?.(color)}
|
||||
syncStatus={syncStatus}
|
||||
syncErrorMessage={syncErrorMessage}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user