From da03f221ae0416bb71abfb3b208df6448bbc617e Mon Sep 17 00:00:00 2001 From: natreex Date: Thu, 15 Jan 2026 19:26:09 -0500 Subject: [PATCH] Remove unused `OfflineIndicator`, `OfflineSyncDetails`, and `OfflineSyncManager` components - Deleted obsolete offline-related components as they are no longer in use. - Simplified imports and removed related context dependencies. - Updated synchronization and toggle switch handling in `CharacterComponent`, `WorldSetting`, and `LocationComponent` to improve consistency. --- app/login/LoginWrapper.tsx | 2 +- .../characters/CharacterComponent.tsx | 21 +- .../settings/guide-line/GuideLineSetting.tsx | 6 +- .../settings/locations/LocationComponent.tsx | 21 +- .../book/settings/world/WorldSetting.tsx | 21 +- components/form/ToggleSwitch.tsx | 72 ++---- components/offline/OfflineIndicator.tsx | 174 ------------- components/offline/OfflineSyncDetails.tsx | 126 ---------- components/offline/OfflineSyncManager.tsx | 233 ------------------ 9 files changed, 68 insertions(+), 608 deletions(-) delete mode 100644 components/offline/OfflineIndicator.tsx delete mode 100644 components/offline/OfflineSyncDetails.tsx delete mode 100644 components/offline/OfflineSyncManager.tsx diff --git a/app/login/LoginWrapper.tsx b/app/login/LoginWrapper.tsx index eaec043..6d19dd9 100644 --- a/app/login/LoginWrapper.tsx +++ b/app/login/LoginWrapper.tsx @@ -57,7 +57,7 @@ export default function LoginWrapper({children}: { children: React.ReactNode }) - + {children}
{ diff --git a/components/book/settings/characters/CharacterComponent.tsx b/components/book/settings/characters/CharacterComponent.tsx index ae09060..e061e82 100644 --- a/components/book/settings/characters/CharacterComponent.tsx +++ b/components/book/settings/characters/CharacterComponent.tsx @@ -14,6 +14,8 @@ import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQ import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext"; import {SyncedBook} from "@/lib/models/SyncedBook"; import ToggleSwitch from "@/components/form/ToggleSwitch"; +import InputField from "@/components/form/InputField"; +import {faToggleOn} from "@fortawesome/free-solid-svg-icons"; interface CharacterDetailProps { selectedCharacter: CharacterProps | null; @@ -366,13 +368,20 @@ export function CharacterComponent({showToggle = true}: {showToggle?: boolean}, return (
{showToggle && ( -
- + => handleToggleTool(checked)} + /> + } /> +

+ {t('characterComponent.enableToolDescription')} +

)} {toolEnabled && ( diff --git a/components/book/settings/guide-line/GuideLineSetting.tsx b/components/book/settings/guide-line/GuideLineSetting.tsx index a835db6..d670878 100644 --- a/components/book/settings/guide-line/GuideLineSetting.tsx +++ b/components/book/settings/guide-line/GuideLineSetting.tsx @@ -93,13 +93,13 @@ function GuideLineSetting(props: any, ref: any) { } } if (response) { - setPlotSummary(response.globalResume); + setPlotSummary(response.globalResume || ''); setVerbTense(response.verbeTense?.toString() || ''); setNarrativeType(response.narrativeType?.toString() || ''); setDialogueType(response.dialogueType?.toString() || ''); - setToneAtmosphere(response.atmosphere); + setToneAtmosphere(response.atmosphere || ''); setLanguage(response.langue?.toString() || ''); - setThemes(response.themes); + setThemes(response.themes || ''); } } catch (e: unknown) { if (e instanceof Error) { diff --git a/components/book/settings/locations/LocationComponent.tsx b/components/book/settings/locations/LocationComponent.tsx index f49a5a4..0909719 100644 --- a/components/book/settings/locations/LocationComponent.tsx +++ b/components/book/settings/locations/LocationComponent.tsx @@ -1,5 +1,5 @@ 'use client' -import {faMapMarkerAlt, faPlus, faTrash} from '@fortawesome/free-solid-svg-icons'; +import {faMapMarkerAlt, faPlus, faToggleOn, faTrash} from '@fortawesome/free-solid-svg-icons'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {ChangeEvent, forwardRef, useContext, useEffect, useImperativeHandle, useState} from 'react'; import {SessionContext} from "@/context/SessionContext"; @@ -477,13 +477,20 @@ export function LocationComponent({showToggle = true}: {showToggle?: boolean}, r return (
{showToggle && ( -
- + => handleToggleTool(checked)} + /> + } /> +

+ {t('locationComponent.enableToolDescription')} +

)} {toolEnabled && ( diff --git a/components/book/settings/world/WorldSetting.tsx b/components/book/settings/world/WorldSetting.tsx index b2989ee..8504b70 100644 --- a/components/book/settings/world/WorldSetting.tsx +++ b/components/book/settings/world/WorldSetting.tsx @@ -1,7 +1,7 @@ 'use client' import {ChangeEvent, forwardRef, useContext, useEffect, useImperativeHandle, useState} from 'react'; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faPlus, IconDefinition} from "@fortawesome/free-solid-svg-icons"; +import {faPlus, faToggleOn, IconDefinition} from "@fortawesome/free-solid-svg-icons"; import {WorldContext} from '@/context/WorldContext'; import {BookContext} from "@/context/BookContext"; import {AlertContext} from "@/context/AlertContext"; @@ -242,13 +242,20 @@ export function WorldSetting({showToggle = true}: {showToggle?: boolean}, ref: a return (
{showToggle && ( -
- + => handleToggleTool(checked)} + /> + } /> +

+ {t('worldSetting.enableToolDescription')} +

)} {toolEnabled && ( diff --git a/components/form/ToggleSwitch.tsx b/components/form/ToggleSwitch.tsx index e263ae6..82bf046 100644 --- a/components/form/ToggleSwitch.tsx +++ b/components/form/ToggleSwitch.tsx @@ -1,59 +1,29 @@ -'use client'; - -import {Dispatch, SetStateAction} from 'react'; +'use client' +import React from "react"; interface ToggleSwitchProps { - enabled: boolean; - setEnabled: Dispatch>; - label?: string; - description?: string; + checked: boolean; + onChange: (checked: boolean) => void; disabled?: boolean; } -export default function ToggleSwitch({ - enabled, - setEnabled, - label, - description, - disabled = false -}: ToggleSwitchProps) { - function handleToggle(): void { - if (!disabled) { - setEnabled(!enabled); - } - } - +export default function ToggleSwitch({checked, onChange, disabled = false}: ToggleSwitchProps) { return ( -
-
- {label && ( - {label} - )} - {description && ( - {description} - )} -
- -
+ ); } diff --git a/components/offline/OfflineIndicator.tsx b/components/offline/OfflineIndicator.tsx deleted file mode 100644 index 26e8fa3..0000000 --- a/components/offline/OfflineIndicator.tsx +++ /dev/null @@ -1,174 +0,0 @@ -'use client'; - -import React, { useContext } from 'react'; -import OfflineContext from '@/context/OfflineContext'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faWifi, faWifiSlash, faSync, faCircle, faExclamationTriangle, faCheck } from '@fortawesome/free-solid-svg-icons'; - -/** - * OfflineIndicator - Displays current online/offline status and sync progress - * Allows user to toggle manual offline mode - */ -export default function OfflineIndicator() { - const { offlineMode, toggleOfflineMode, syncNow } = useContext(OfflineContext); - - const { - isOffline, - isManuallyOffline, - isNetworkOnline, - isDatabaseInitialized, - syncProgress, - lastSyncAt, - error - } = offlineMode; - - // Determine status color and text - const getStatusInfo = () => { - if (!isDatabaseInitialized) { - return { - color: 'text-gray-400', - bgColor: 'bg-gray-100', - icon: faCircle, - text: 'DB non initialisée' - }; - } - - if (error) { - return { - color: 'text-red-500', - bgColor: 'bg-red-50', - icon: faExclamationTriangle, - text: 'Erreur de sync' - }; - } - - if (syncProgress.isSyncing) { - return { - color: 'text-blue-500', - bgColor: 'bg-blue-50', - icon: faSync, - text: 'Synchronisation...', - spin: true - }; - } - - if (isOffline) { - if (syncProgress.pendingChanges > 0) { - return { - color: 'text-orange-500', - bgColor: 'bg-orange-50', - icon: faWifiSlash, - text: `Hors ligne (${syncProgress.pendingChanges} en attente)` - }; - } - return { - color: 'text-orange-500', - bgColor: 'bg-orange-50', - icon: faWifiSlash, - text: isManuallyOffline ? 'Mode hors ligne' : 'Hors ligne' - }; - } - - if (syncProgress.pendingChanges > 0) { - return { - color: 'text-yellow-500', - bgColor: 'bg-yellow-50', - icon: faSync, - text: `${syncProgress.pendingChanges} changements à sync` - }; - } - - return { - color: 'text-green-500', - bgColor: 'bg-green-50', - icon: faCheck, - text: 'Synchronisé' - }; - }; - - const statusInfo = getStatusInfo(); - - // Format last sync time - const formatLastSync = () => { - if (!lastSyncAt) return 'Jamais'; - - const diff = Date.now() - lastSyncAt; - const minutes = Math.floor(diff / 60000); - const hours = Math.floor(minutes / 60); - - if (hours > 0) return `Il y a ${hours}h`; - if (minutes > 0) return `Il y a ${minutes}min`; - return 'À l\'instant'; - }; - - const handleSyncNow = async () => { - if (!isOffline && !syncProgress.isSyncing) { - await syncNow(); - } - }; - - return ( -
- {/* Status indicator */} -
- - - {statusInfo.text} - -
- - {/* Last sync time */} - {isDatabaseInitialized && !isOffline && ( - - Dernière sync: {formatLastSync()} - - )} - - {/* Error message */} - {error && ( - - {error} - - )} - - {/* Actions */} -
- {/* Manual sync button */} - {isDatabaseInitialized && !isOffline && !syncProgress.isSyncing && ( - - )} - - {/* Offline toggle */} - {isDatabaseInitialized && ( - - )} -
-
- ); -} diff --git a/components/offline/OfflineSyncDetails.tsx b/components/offline/OfflineSyncDetails.tsx deleted file mode 100644 index 3e5792a..0000000 --- a/components/offline/OfflineSyncDetails.tsx +++ /dev/null @@ -1,126 +0,0 @@ -'use client'; - -import React, { useContext } from 'react'; -import OfflineContext from '@/context/OfflineContext'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faDatabase, faSync, faExclamationCircle } from '@fortawesome/free-solid-svg-icons'; - -/** - * OfflineSyncDetails - Detailed view of sync status per table - * Shows pending changes and last sync time for each data type - */ -export default function OfflineSyncDetails() { - const { offlineMode } = useContext(OfflineContext); - const { syncProgress, isDatabaseInitialized } = offlineMode; - - if (!isDatabaseInitialized) { - return ( -
- -

Base de données non initialisée

-
- ); - } - - if (!syncProgress.tables || syncProgress.tables.length === 0) { - return ( -
- -

Aucune donnée de synchronisation disponible

-
- ); - } - - // Format timestamp - const formatTime = (timestamp: number) => { - if (!timestamp) return 'Jamais'; - const date = new Date(timestamp); - return date.toLocaleString('fr-FR', { - day: '2-digit', - month: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }); - }; - - // Get friendly name for table - const getTableName = (table: string): string => { - const names: { [key: string]: string } = { - 'erit_books': 'Livres', - 'book_chapters': 'Chapitres', - 'book_chapter_content': 'Contenu des chapitres', - 'book_characters': 'Personnages', - 'book_world': 'Monde', - 'book_world_elements': 'Éléments du monde', - 'ai_conversations': 'Conversations IA', - 'ai_messages_history': 'Messages IA', - 'book_guide_line': 'Lignes directrices', - 'book_plot_points': 'Points de l\'intrigue', - 'book_incidents': 'Incidents' - }; - return names[table] || table; - }; - - return ( -
-

- - État de synchronisation -

- -
- {syncProgress.tables.map((tableStatus) => { - const hasPending = tableStatus.pending > 0; - - return ( -
-
-
-
- {getTableName(tableStatus.table)} -
-
- Dernière sync: {formatTime(tableStatus.lastSync)} -
-
- - {hasPending && ( -
- - - {tableStatus.pending} en attente - -
- )} - - {!hasPending && tableStatus.lastSync > 0 && ( -
- ✓ Synchronisé -
- )} -
-
- ); - })} -
- - {/* Summary */} -
-
- Total: {syncProgress.pendingChanges} changement(s) en attente -
-
-
- ); -} diff --git a/components/offline/OfflineSyncManager.tsx b/components/offline/OfflineSyncManager.tsx deleted file mode 100644 index c134bd9..0000000 --- a/components/offline/OfflineSyncManager.tsx +++ /dev/null @@ -1,233 +0,0 @@ -'use client'; -import { useState, useEffect, useContext } from 'react'; -import { SessionContext } from '@/context/SessionContext'; -import { OfflineContext } from '@/context/OfflineContext'; -import { useTranslations } from 'next-intl'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { - faCloudDownloadAlt, - faWifi, - faCheckCircle, - faSpinner, - faBook -} from '@fortawesome/free-solid-svg-icons'; - -interface SyncOption { - id: 'current' | 'recent' | 'all' | 'skip'; - label: string; - description: string; - estimatedSize?: string; - bookCount?: number; -} - -export default function OfflineSyncManager() { - const t = useTranslations(); - const { session } = useContext(SessionContext); - const { syncBooks, isOnline } = useContext(OfflineContext); - const [showDialog, setShowDialog] = useState(false); - const [isFirstSync, setIsFirstSync] = useState(false); - const [syncProgress, setSyncProgress] = useState(0); - const [selectedOption, setSelectedOption] = useState(''); - - useEffect(() => { - // Check if this is first time user sees sync options - const hasSeenSync = localStorage.getItem('hasSeenSyncDialog'); - if (!hasSeenSync && isOnline && session?.user) { - setIsFirstSync(true); - setShowDialog(true); - } - }, [session, isOnline]); - - const syncOptions: SyncOption[] = [ - { - id: 'current', - label: t('sync.currentBook'), - description: t('sync.currentBookDesc'), - estimatedSize: '~5 MB', - bookCount: 1 - }, - { - id: 'recent', - label: t('sync.recentBooks'), - description: t('sync.recentBooksDesc'), - estimatedSize: '~25 MB', - bookCount: 3 - }, - { - id: 'all', - label: t('sync.allBooks'), - description: t('sync.allBooksDesc'), - estimatedSize: '~120 MB', - bookCount: 12 - }, - { - id: 'skip', - label: t('sync.skipForNow'), - description: t('sync.skipDesc'), - } - ]; - - const handleSync = async (option: string) => { - if (option === 'skip') { - localStorage.setItem('hasSeenSyncDialog', 'true'); - setShowDialog(false); - return; - } - - setSyncProgress(0); - - try { - // Simulate progressive download - const interval = setInterval(() => { - setSyncProgress(prev => { - if (prev >= 100) { - clearInterval(interval); - return 100; - } - return prev + 10; - }); - }, 200); - - // Actual sync logic here - // await syncBooks(option); - - localStorage.setItem('hasSeenSyncDialog', 'true'); - localStorage.setItem('syncPreference', option); - - setTimeout(() => { - setShowDialog(false); - }, 2000); - } catch (error) { - console.error('Sync failed:', error); - } - }; - - if (!showDialog) return null; - - return ( -
-
- {/* Header */} -
-
- - {isOnline && ( - - )} -
-
-

- {isFirstSync ? t('sync.welcomeOffline') : t('sync.syncOptions')} -

-

- {t('sync.workAnywhere')} -

-
-
- - {/* Sync Options */} - {syncProgress === 0 ? ( -
- {syncOptions.map((option) => ( - - ))} -
- ) : ( - /* Progress Bar */ -
-
- - {t('sync.downloading')}... - - - {syncProgress}% - -
-
-
-
- {syncProgress === 100 && ( -
- -

- {t('sync.complete')}! -

-
- )} -
- )} - - {/* Actions */} - {syncProgress === 0 && ( -
- - -
- )} -
-
- ); -} \ No newline at end of file