diff --git a/src/components/ReduxIntegrationDemo.tsx b/src/components/ReduxIntegrationDemo.tsx
index 9ec3826..3c60706 100644
--- a/src/components/ReduxIntegrationDemo.tsx
+++ b/src/components/ReduxIntegrationDemo.tsx
@@ -1,39 +1,29 @@
import { useEffect } from 'react'
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
-import { Button } from '@/components/ui/button'
-import { Badge } from '@/components/ui/badge'
-import { Separator } from '@/components/ui/separator'
import { toast } from 'sonner'
-import {
- ArrowsClockwise,
- Database,
- CloudArrowUp,
- CloudArrowDown,
- CheckCircle,
- XCircle,
- Clock,
- Trash,
- FilePlus
-} from '@phosphor-icons/react'
import { useReduxFiles } from '@/hooks/use-redux-files'
import { useReduxComponentTrees } from '@/hooks/use-redux-component-trees'
import { useReduxSync } from '@/hooks/use-redux-sync'
import { useAppSelector } from '@/store'
+import { ComponentTreesCard } from '@/components/redux-integration/ComponentTreesCard'
+import { DangerZoneCard } from '@/components/redux-integration/DangerZoneCard'
+import { FilesCard } from '@/components/redux-integration/FilesCard'
+import { ReduxIntegrationHeader } from '@/components/redux-integration/ReduxIntegrationHeader'
+import { StatusCardsSection } from '@/components/redux-integration/StatusCardsSection'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
export function ReduxIntegrationDemo() {
const { files, load: loadFiles, save: saveFile, remove: removeFile } = useReduxFiles()
const { trees, load: loadTrees } = useReduxComponentTrees()
- const {
- status,
- lastSyncedAt,
- flaskConnected,
+ const {
+ status,
+ lastSyncedAt,
+ flaskConnected,
flaskStats,
- syncToFlask,
+ syncToFlask,
syncFromFlask,
checkConnection,
- clearFlaskData
+ clearFlaskData,
} = useReduxSync()
-
const settings = useAppSelector((state) => state.settings.settings)
useEffect(() => {
@@ -51,284 +41,49 @@ export function ReduxIntegrationDemo() {
updatedAt: Date.now(),
}
saveFile(newFile)
- toast.success('Test file created and saved to IndexedDB')
+ toast.success(reduxIntegrationCopy.toast.createTestFile)
}
const handleDeleteFile = (fileId: string) => {
removeFile(fileId)
- toast.success('File deleted from IndexedDB')
+ toast.success(reduxIntegrationCopy.toast.deleteFile)
}
const handleSyncUp = () => {
syncToFlask()
- toast.info('Syncing to Flask API...')
+ toast.info(reduxIntegrationCopy.toast.syncUp)
}
const handleSyncDown = () => {
syncFromFlask()
- toast.info('Syncing from Flask API...')
+ toast.info(reduxIntegrationCopy.toast.syncDown)
}
const handleClearFlask = () => {
clearFlaskData()
- toast.warning('Clearing Flask storage...')
- }
-
- const getSyncStatusBadge = () => {
- switch (status) {
- case 'idle':
- return Idle
- case 'syncing':
- return Syncing...
- case 'success':
- return Success
- case 'error':
- return Error
- }
- }
-
- const getConnectionBadge = () => {
- return flaskConnected ? (
-
- Connected
-
- ) : (
-
- Disconnected
-
- )
+ toast.warning(reduxIntegrationCopy.toast.clearFlask)
}
return (
-
-
Redux Integration Demo
-
- Comprehensive Redux Toolkit integration with IndexedDB and Flask API synchronization
-
-
-
-
-
-
-
-
- IndexedDB Status
-
- Local browser storage
-
-
-
- Files
- {files.length}
-
-
- Component Trees
- {trees.length}
-
-
-
-
-
-
-
-
-
-
- Flask API Status
-
- Remote server connection
-
-
-
- Connection
- {getConnectionBadge()}
-
- {flaskStats && (
- <>
-
- Total Keys
- {flaskStats.totalKeys}
-
-
- Storage Size
-
- {(flaskStats.totalSizeBytes / 1024).toFixed(2)} KB
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
- Sync Status
-
- Data synchronization
-
-
-
- Status
- {getSyncStatusBadge()}
-
-
- Auto Sync
-
- {settings.autoSync ? 'Enabled' : 'Disabled'}
-
-
- {lastSyncedAt && (
-
- Last Sync
-
-
- {new Date(lastSyncedAt).toLocaleTimeString()}
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- Files in Redux Store
-
- Files managed by Redux and synced with IndexedDB/Flask
-
-
-
- {files.length === 0 ? (
-
-
-
No files yet. Create a test file to get started.
-
- ) : (
-
- {files.map((file) => (
-
-
-
{file.name}
-
- {file.path} • Updated {new Date(file.updatedAt).toLocaleString()}
-
-
-
-
- ))}
-
- )}
-
-
-
-
-
- Component Trees in Redux Store
-
- JSON component trees loaded from components.json
-
-
-
- {trees.length === 0 ? (
-
-
-
No component trees loaded yet.
-
- ) : (
-
- {trees.map((tree) => (
-
-
-
{tree.name}
- {tree.description && (
-
{tree.description}
- )}
-
-
- {tree.root.type}
-
-
- ))}
-
- )}
-
-
-
-
-
- Danger Zone
-
- Irreversible operations - use with caution
-
-
-
-
-
-
+
+
+
+
+
)
diff --git a/src/components/redux-integration/ComponentTreesCard.tsx b/src/components/redux-integration/ComponentTreesCard.tsx
new file mode 100644
index 0000000..e07bb1c
--- /dev/null
+++ b/src/components/redux-integration/ComponentTreesCard.tsx
@@ -0,0 +1,45 @@
+import { Badge } from '@/components/ui/badge'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Database } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+import { ComponentTree } from '@/store/slices/componentTreesSlice'
+
+type ComponentTreesCardProps = {
+ trees: ComponentTree[]
+}
+
+export function ComponentTreesCard({ trees }: ComponentTreesCardProps) {
+ return (
+
+
+ {reduxIntegrationCopy.componentTrees.title}
+ {reduxIntegrationCopy.componentTrees.description}
+
+
+ {trees.length === 0 ? (
+
+
+
{reduxIntegrationCopy.componentTrees.empty}
+
+ ) : (
+
+ {trees.map((tree) => (
+
+
+
{tree.name}
+ {tree.description && (
+
{tree.description}
+ )}
+
+
{tree.root.type}
+
+ ))}
+
+ )}
+
+
+ )
+}
diff --git a/src/components/redux-integration/DangerZoneCard.tsx b/src/components/redux-integration/DangerZoneCard.tsx
new file mode 100644
index 0000000..acc53b7
--- /dev/null
+++ b/src/components/redux-integration/DangerZoneCard.tsx
@@ -0,0 +1,26 @@
+import { Button } from '@/components/ui/button'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Trash } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+
+type DangerZoneCardProps = {
+ flaskConnected: boolean
+ onClearFlask: () => void
+}
+
+export function DangerZoneCard({ flaskConnected, onClearFlask }: DangerZoneCardProps) {
+ return (
+
+
+ {reduxIntegrationCopy.danger.title}
+ {reduxIntegrationCopy.danger.description}
+
+
+
+
+
+ )
+}
diff --git a/src/components/redux-integration/FilesCard.tsx b/src/components/redux-integration/FilesCard.tsx
new file mode 100644
index 0000000..41d9464
--- /dev/null
+++ b/src/components/redux-integration/FilesCard.tsx
@@ -0,0 +1,50 @@
+import { Badge } from '@/components/ui/badge'
+import { Button } from '@/components/ui/button'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Database, Trash } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+import { FileItem } from '@/store/slices/filesSlice'
+
+type FilesCardProps = {
+ files: FileItem[]
+ onDeleteFile: (fileId: string) => void
+}
+
+export function FilesCard({ files, onDeleteFile }: FilesCardProps) {
+ return (
+
+
+ {reduxIntegrationCopy.files.title}
+ {reduxIntegrationCopy.files.description}
+
+
+ {files.length === 0 ? (
+
+
+
{reduxIntegrationCopy.files.empty}
+
+ ) : (
+
+ {files.map((file) => (
+
+
+
{file.name}
+
+ {file.path} • {reduxIntegrationCopy.files.updatedLabel}{' '}
+ {new Date(file.updatedAt).toLocaleString()}
+
+
+
+
+ ))}
+
+ )}
+
+
+ )
+}
diff --git a/src/components/redux-integration/FlaskStatusCard.tsx b/src/components/redux-integration/FlaskStatusCard.tsx
new file mode 100644
index 0000000..d261292
--- /dev/null
+++ b/src/components/redux-integration/FlaskStatusCard.tsx
@@ -0,0 +1,76 @@
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Button } from '@/components/ui/button'
+import { Badge } from '@/components/ui/badge'
+import { Separator } from '@/components/ui/separator'
+import { ArrowsClockwise, CheckCircle, CloudArrowUp, XCircle } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+type FlaskStats = {
+ totalKeys: number
+ totalSizeBytes: number
+} | null
+
+type FlaskStatusCardProps = {
+ flaskConnected: boolean
+ flaskStats: FlaskStats
+ onCheckConnection: () => void
+}
+
+export function FlaskStatusCard({ flaskConnected, flaskStats, onCheckConnection }: FlaskStatusCardProps) {
+ const connectionLabel = flaskConnected
+ ? reduxIntegrationCopy.cards.flask.status.connected
+ : reduxIntegrationCopy.cards.flask.status.disconnected
+
+ return (
+
+
+
+
+ {reduxIntegrationCopy.cards.flask.title}
+
+ {reduxIntegrationCopy.cards.flask.description}
+
+
+
+
+ {reduxIntegrationCopy.cards.flask.labels.connection}
+
+ {flaskConnected ? (
+
+
+ {connectionLabel}
+
+ ) : (
+
+
+ {connectionLabel}
+
+ )}
+
+ {flaskStats && (
+ <>
+
+
+ {reduxIntegrationCopy.cards.flask.labels.totalKeys}
+
+ {flaskStats.totalKeys}
+
+
+
+ {reduxIntegrationCopy.cards.flask.labels.storageSize}
+
+
+ {(flaskStats.totalSizeBytes / 1024).toFixed(2)}{' '}
+ {reduxIntegrationCopy.cards.flask.labels.storageUnit}
+
+
+ >
+ )}
+
+
+
+
+ )
+}
diff --git a/src/components/redux-integration/IndexedDbStatusCard.tsx b/src/components/redux-integration/IndexedDbStatusCard.tsx
new file mode 100644
index 0000000..914b375
--- /dev/null
+++ b/src/components/redux-integration/IndexedDbStatusCard.tsx
@@ -0,0 +1,49 @@
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Button } from '@/components/ui/button'
+import { Badge } from '@/components/ui/badge'
+import { Separator } from '@/components/ui/separator'
+import { Database, FilePlus } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+
+type IndexedDbStatusCardProps = {
+ filesCount: number
+ treesCount: number
+ onCreateTestFile: () => void
+}
+
+export function IndexedDbStatusCard({
+ filesCount,
+ treesCount,
+ onCreateTestFile,
+}: IndexedDbStatusCardProps) {
+ return (
+
+
+
+
+ {reduxIntegrationCopy.cards.indexedDb.title}
+
+ {reduxIntegrationCopy.cards.indexedDb.description}
+
+
+
+
+ {reduxIntegrationCopy.cards.indexedDb.labels.files}
+
+ {filesCount}
+
+
+
+ {reduxIntegrationCopy.cards.indexedDb.labels.componentTrees}
+
+ {treesCount}
+
+
+
+
+
+ )
+}
diff --git a/src/components/redux-integration/ReduxIntegrationHeader.tsx b/src/components/redux-integration/ReduxIntegrationHeader.tsx
new file mode 100644
index 0000000..1e9573b
--- /dev/null
+++ b/src/components/redux-integration/ReduxIntegrationHeader.tsx
@@ -0,0 +1,10 @@
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+
+export function ReduxIntegrationHeader() {
+ return (
+
+
{reduxIntegrationCopy.page.title}
+
{reduxIntegrationCopy.page.description}
+
+ )
+}
diff --git a/src/components/redux-integration/StatusCardsSection.tsx b/src/components/redux-integration/StatusCardsSection.tsx
new file mode 100644
index 0000000..dd3010f
--- /dev/null
+++ b/src/components/redux-integration/StatusCardsSection.tsx
@@ -0,0 +1,60 @@
+import { IndexedDbStatusCard } from '@/components/redux-integration/IndexedDbStatusCard'
+import { FlaskStatusCard } from '@/components/redux-integration/FlaskStatusCard'
+import { SyncStatusCard } from '@/components/redux-integration/SyncStatusCard'
+import { SyncStatus } from '@/store/slices/syncSlice'
+
+type FlaskStats = {
+ totalKeys: number
+ totalSizeBytes: number
+} | null
+
+type StatusCardsSectionProps = {
+ filesCount: number
+ treesCount: number
+ flaskConnected: boolean
+ flaskStats: FlaskStats
+ status: SyncStatus
+ lastSyncedAt: number | null
+ autoSyncEnabled: boolean
+ onCreateTestFile: () => void
+ onCheckConnection: () => void
+ onSyncUp: () => void
+ onSyncDown: () => void
+}
+
+export function StatusCardsSection({
+ filesCount,
+ treesCount,
+ flaskConnected,
+ flaskStats,
+ status,
+ lastSyncedAt,
+ autoSyncEnabled,
+ onCreateTestFile,
+ onCheckConnection,
+ onSyncUp,
+ onSyncDown,
+}: StatusCardsSectionProps) {
+ return (
+
+
+
+
+
+ )
+}
diff --git a/src/components/redux-integration/SyncStatusCard.tsx b/src/components/redux-integration/SyncStatusCard.tsx
new file mode 100644
index 0000000..50673b4
--- /dev/null
+++ b/src/components/redux-integration/SyncStatusCard.tsx
@@ -0,0 +1,116 @@
+import { Badge } from '@/components/ui/badge'
+import { Button } from '@/components/ui/button'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Separator } from '@/components/ui/separator'
+import { ArrowsClockwise, CheckCircle, Clock, CloudArrowDown, CloudArrowUp, XCircle } from '@phosphor-icons/react'
+import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
+import { SyncStatus } from '@/store/slices/syncSlice'
+
+type SyncStatusCardProps = {
+ status: SyncStatus
+ lastSyncedAt: number | null
+ autoSyncEnabled: boolean
+ flaskConnected: boolean
+ onSyncUp: () => void
+ onSyncDown: () => void
+}
+
+export function SyncStatusCard({
+ status,
+ lastSyncedAt,
+ autoSyncEnabled,
+ flaskConnected,
+ onSyncUp,
+ onSyncDown,
+}: SyncStatusCardProps) {
+ const getSyncStatusBadge = () => {
+ switch (status) {
+ case 'idle':
+ return {reduxIntegrationCopy.cards.sync.status.idle}
+ case 'syncing':
+ return (
+
+ {reduxIntegrationCopy.cards.sync.status.syncing}
+
+ )
+ case 'success':
+ return (
+
+
+ {reduxIntegrationCopy.cards.sync.status.success}
+
+ )
+ case 'error':
+ return (
+
+
+ {reduxIntegrationCopy.cards.sync.status.error}
+
+ )
+ }
+ }
+
+ return (
+
+
+
+
+ {reduxIntegrationCopy.cards.sync.title}
+
+ {reduxIntegrationCopy.cards.sync.description}
+
+
+
+
+ {reduxIntegrationCopy.cards.sync.labels.status}
+
+ {getSyncStatusBadge()}
+
+
+
+ {reduxIntegrationCopy.cards.sync.labels.autoSync}
+
+
+ {autoSyncEnabled
+ ? reduxIntegrationCopy.cards.sync.autoSync.enabled
+ : reduxIntegrationCopy.cards.sync.autoSync.disabled}
+
+
+ {lastSyncedAt && (
+
+
+ {reduxIntegrationCopy.cards.sync.labels.lastSync}
+
+
+
+ {new Date(lastSyncedAt).toLocaleTimeString()}
+
+
+ )}
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/data/redux-integration-demo.json b/src/data/redux-integration-demo.json
new file mode 100644
index 0000000..fa42cb1
--- /dev/null
+++ b/src/data/redux-integration-demo.json
@@ -0,0 +1,76 @@
+{
+ "page": {
+ "title": "Redux Integration Demo",
+ "description": "Comprehensive Redux Toolkit integration with IndexedDB and Flask API synchronization"
+ },
+ "cards": {
+ "indexedDb": {
+ "title": "IndexedDB Status",
+ "description": "Local browser storage",
+ "labels": {
+ "files": "Files",
+ "componentTrees": "Component Trees",
+ "createTestFile": "Create Test File"
+ }
+ },
+ "flask": {
+ "title": "Flask API Status",
+ "description": "Remote server connection",
+ "labels": {
+ "connection": "Connection",
+ "totalKeys": "Total Keys",
+ "storageSize": "Storage Size",
+ "storageUnit": "KB",
+ "checkConnection": "Check Connection"
+ },
+ "status": {
+ "connected": "Connected",
+ "disconnected": "Disconnected"
+ }
+ },
+ "sync": {
+ "title": "Sync Status",
+ "description": "Data synchronization",
+ "labels": {
+ "status": "Status",
+ "autoSync": "Auto Sync",
+ "lastSync": "Last Sync",
+ "push": "Push",
+ "pull": "Pull"
+ },
+ "status": {
+ "idle": "Idle",
+ "syncing": "Syncing...",
+ "success": "Success",
+ "error": "Error"
+ },
+ "autoSync": {
+ "enabled": "Enabled",
+ "disabled": "Disabled"
+ }
+ }
+ },
+ "files": {
+ "title": "Files in Redux Store",
+ "description": "Files managed by Redux and synced with IndexedDB/Flask",
+ "empty": "No files yet. Create a test file to get started.",
+ "updatedLabel": "Updated"
+ },
+ "componentTrees": {
+ "title": "Component Trees in Redux Store",
+ "description": "JSON component trees loaded from components.json",
+ "empty": "No component trees loaded yet."
+ },
+ "danger": {
+ "title": "Danger Zone",
+ "description": "Irreversible operations - use with caution",
+ "clearButton": "Clear Flask Storage"
+ },
+ "toast": {
+ "createTestFile": "Test file created and saved to IndexedDB",
+ "deleteFile": "File deleted from IndexedDB",
+ "syncUp": "Syncing to Flask API...",
+ "syncDown": "Syncing from Flask API...",
+ "clearFlask": "Clearing Flask storage..."
+ }
+}