mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-02-14 04:37:32 +00:00
refactor: Restructure files and folders to better mimic feature-based architecture
This commit is contained in:
@@ -2,8 +2,8 @@ import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Sidebar from '../Sidebar';
|
||||
import MainContent from '../MainContent';
|
||||
import Sidebar from '../sidebar/view/Sidebar';
|
||||
import MainContent from '../main-content/view/MainContent';
|
||||
import MobileNav from '../MobileNav';
|
||||
|
||||
import { useWebSocket } from '../../contexts/WebSocketContext';
|
||||
|
||||
@@ -10,19 +10,19 @@ import type {
|
||||
TouchEvent,
|
||||
} from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { authenticatedFetch } from '../../utils/api';
|
||||
import { thinkingModes } from '../../components/ThinkingModeSelector.jsx';
|
||||
import { grantClaudeToolPermission } from '../../components/chat/utils/chatPermissions';
|
||||
import { safeLocalStorage } from '../../components/chat/utils/chatStorage';
|
||||
import { authenticatedFetch } from '../../../utils/api';
|
||||
import { thinkingModes } from '../../ThinkingModeSelector.jsx';
|
||||
import { grantClaudeToolPermission } from '../utils/chatPermissions';
|
||||
import { safeLocalStorage } from '../utils/chatStorage';
|
||||
import type {
|
||||
ChatMessage,
|
||||
PendingPermissionRequest,
|
||||
PermissionMode,
|
||||
Provider,
|
||||
} from '../../components/chat/types';
|
||||
} from '../types';
|
||||
import { useFileMentions } from './useFileMentions';
|
||||
import { type SlashCommand, useSlashCommands } from './useSlashCommands';
|
||||
import type { Project, ProjectSession } from '../../types/app';
|
||||
import type { Project, ProjectSession } from '../../../types/app';
|
||||
|
||||
type PendingViewSession = {
|
||||
sessionId: string | null;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { authenticatedFetch } from '../../utils/api';
|
||||
import { CLAUDE_MODELS, CODEX_MODELS, CURSOR_MODELS } from '../../../shared/modelConstants';
|
||||
import type { PendingPermissionRequest, PermissionMode, Provider } from '../../components/chat/types';
|
||||
import type { ProjectSession } from '../../types/app';
|
||||
import { authenticatedFetch } from '../../../utils/api';
|
||||
import { CLAUDE_MODELS, CODEX_MODELS, CURSOR_MODELS } from '../../../../shared/modelConstants';
|
||||
import type { PendingPermissionRequest, PermissionMode, Provider } from '../types';
|
||||
import type { ProjectSession } from '../../../types/app';
|
||||
|
||||
interface UseChatProviderStateArgs {
|
||||
selectedSession: ProjectSession | null;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||
import { decodeHtmlEntities, formatUsageLimitText } from '../../components/chat/utils/chatFormatting';
|
||||
import { safeLocalStorage } from '../../components/chat/utils/chatStorage';
|
||||
import type { ChatMessage, PendingPermissionRequest, Provider } from '../../components/chat/types';
|
||||
import type { Project, ProjectSession } from '../../types/app';
|
||||
import { decodeHtmlEntities, formatUsageLimitText } from '../utils/chatFormatting';
|
||||
import { safeLocalStorage } from '../utils/chatStorage';
|
||||
import type { ChatMessage, PendingPermissionRequest, Provider } from '../types';
|
||||
import type { Project, ProjectSession } from '../../../types/app';
|
||||
|
||||
type PendingViewSession = {
|
||||
sessionId: string | null;
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import type { MutableRefObject } from 'react';
|
||||
import { api, authenticatedFetch } from '../../utils/api';
|
||||
import type { ChatMessage, Provider } from '../../components/chat/types';
|
||||
import type { Project, ProjectSession } from '../../types/app';
|
||||
import { safeLocalStorage } from '../../components/chat/utils/chatStorage';
|
||||
import { api, authenticatedFetch } from '../../../utils/api';
|
||||
import type { ChatMessage, Provider } from '../types';
|
||||
import type { Project, ProjectSession } from '../../../types/app';
|
||||
import { safeLocalStorage } from '../utils/chatStorage';
|
||||
import {
|
||||
convertCursorSessionMessages,
|
||||
convertSessionMessages,
|
||||
createCachedDiffCalculator,
|
||||
type DiffCalculator,
|
||||
} from '../../components/chat/utils/messageTransforms';
|
||||
} from '../utils/messageTransforms';
|
||||
|
||||
const MESSAGES_PER_PAGE = 20;
|
||||
const INITIAL_VISIBLE_MESSAGES = 100;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react';
|
||||
import { api } from '../../utils/api';
|
||||
import { escapeRegExp } from '../../components/chat/utils/chatFormatting';
|
||||
import type { Project } from '../../types/app';
|
||||
import { api } from '../../../utils/api';
|
||||
import { escapeRegExp } from '../utils/chatFormatting';
|
||||
import type { Project } from '../../../types/app';
|
||||
|
||||
interface ProjectFileNode {
|
||||
name: string;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react';
|
||||
import Fuse from 'fuse.js';
|
||||
import { authenticatedFetch } from '../../utils/api';
|
||||
import { safeLocalStorage } from '../../components/chat/utils/chatStorage';
|
||||
import type { Project } from '../../types/app';
|
||||
import { authenticatedFetch } from '../../../utils/api';
|
||||
import { safeLocalStorage } from '../utils/chatStorage';
|
||||
import type { Project } from '../../../types/app';
|
||||
|
||||
const COMMAND_QUERY_DEBOUNCE_MS = 150;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import QuickSettingsPanel from './QuickSettingsPanel';
|
||||
import { useTasksSettings } from '../contexts/TasksSettingsContext';
|
||||
import QuickSettingsPanel from '../../QuickSettingsPanel';
|
||||
import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ChatMessagesPane from './chat/view/ChatMessagesPane';
|
||||
import ChatComposer from './chat/view/ChatComposer';
|
||||
import type { ChatInterfaceProps } from './chat/types';
|
||||
import { useChatProviderState } from '../hooks/chat/useChatProviderState';
|
||||
import { useChatSessionState } from '../hooks/chat/useChatSessionState';
|
||||
import { useChatRealtimeHandlers } from '../hooks/chat/useChatRealtimeHandlers';
|
||||
import { useChatComposerState } from '../hooks/chat/useChatComposerState';
|
||||
import type { Provider } from './chat/types';
|
||||
import ChatMessagesPane from './ChatMessagesPane';
|
||||
import ChatComposer from './ChatComposer';
|
||||
import type { ChatInterfaceProps } from '../types';
|
||||
import { useChatProviderState } from '../hooks/useChatProviderState';
|
||||
import { useChatSessionState } from '../hooks/useChatSessionState';
|
||||
import { useChatRealtimeHandlers } from '../hooks/useChatRealtimeHandlers';
|
||||
import { useChatComposerState } from '../hooks/useChatComposerState';
|
||||
import type { Provider } from '../types';
|
||||
|
||||
type PendingViewSession = {
|
||||
sessionId: string | null;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import type { MouseEvent as ReactMouseEvent } from 'react';
|
||||
import type { Project } from '../../types/app';
|
||||
import type { DiffInfo, EditingFile } from '../../components/main-content/types';
|
||||
import type { Project } from '../../../types/app';
|
||||
import type { DiffInfo, EditingFile } from '../types/types';
|
||||
|
||||
type UseEditorSidebarOptions = {
|
||||
selectedProject: Project | null;
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Dispatch, MouseEvent, RefObject, SetStateAction } from 'react';
|
||||
import type { AppTab, Project, ProjectSession } from '../../types/app';
|
||||
import type { AppTab, Project, ProjectSession } from '../../../types/app';
|
||||
|
||||
export type SessionLifecycleHandler = (sessionId?: string | null) => void;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import ChatInterface from './ChatInterface';
|
||||
import FileTree from './FileTree';
|
||||
import StandaloneShell from './StandaloneShell';
|
||||
import GitPanel from './GitPanel';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import ChatInterface from '../../chat/view/ChatInterface';
|
||||
import FileTree from '../../FileTree';
|
||||
import StandaloneShell from '../../StandaloneShell';
|
||||
import GitPanel from '../../GitPanel';
|
||||
import ErrorBoundary from '../../ErrorBoundary';
|
||||
|
||||
import MainContentHeader from './main-content/MainContentHeader';
|
||||
import MainContentStateView from './main-content/MainContentStateView';
|
||||
import EditorSidebar from './main-content/EditorSidebar';
|
||||
import TaskMasterPanel from './main-content/TaskMasterPanel';
|
||||
import type { MainContentProps } from './main-content/types';
|
||||
import MainContentHeader from './subcomponents/MainContentHeader';
|
||||
import MainContentStateView from './subcomponents/MainContentStateView';
|
||||
import EditorSidebar from './subcomponents/EditorSidebar';
|
||||
import TaskMasterPanel from './subcomponents/TaskMasterPanel';
|
||||
import type { MainContentProps } from '../types/types';
|
||||
|
||||
import { useTaskMaster } from '../contexts/TaskMasterContext';
|
||||
import { useTasksSettings } from '../contexts/TasksSettingsContext';
|
||||
import { useUiPreferences } from '../hooks/useUiPreferences';
|
||||
import { useEditorSidebar } from '../hooks/main-content/useEditorSidebar';
|
||||
import type { Project } from '../types/app';
|
||||
import { useTaskMaster } from '../../../contexts/TaskMasterContext';
|
||||
import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
|
||||
import { useUiPreferences } from '../../../hooks/useUiPreferences';
|
||||
import { useEditorSidebar } from '../hooks/useEditorSidebar';
|
||||
import type { Project } from '../../../types/app';
|
||||
|
||||
const AnyStandaloneShell = StandaloneShell as any;
|
||||
const AnyGitPanel = GitPanel as any;
|
||||
@@ -1,5 +1,5 @@
|
||||
import CodeEditor from '../CodeEditor';
|
||||
import type { EditorSidebarProps } from './types';
|
||||
import CodeEditor from '../../../CodeEditor';
|
||||
import type { EditorSidebarProps } from '../../types/types';
|
||||
|
||||
const AnyCodeEditor = CodeEditor as any;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import MobileMenuButton from './MobileMenuButton';
|
||||
import MainContentTabSwitcher from './MainContentTabSwitcher';
|
||||
import MainContentTitle from './MainContentTitle';
|
||||
import type { MainContentHeaderProps } from './types';
|
||||
import type { MainContentHeaderProps } from '../../types/types';
|
||||
|
||||
export default function MainContentHeader({
|
||||
activeTab,
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import MobileMenuButton from './MobileMenuButton';
|
||||
import type { MainContentStateViewProps } from './types';
|
||||
import type { MainContentStateViewProps } from '../../types/types';
|
||||
|
||||
export default function MainContentStateView({ mode, isMobile, onMenuClick }: MainContentStateViewProps) {
|
||||
const { t } = useTranslation();
|
||||
@@ -1,5 +1,5 @@
|
||||
import Tooltip from '../Tooltip';
|
||||
import type { AppTab } from '../../types/app';
|
||||
import Tooltip from '../../../Tooltip';
|
||||
import type { AppTab } from '../../../../types/app';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import SessionProviderLogo from '../SessionProviderLogo';
|
||||
import type { AppTab, Project, ProjectSession } from '../../types/app';
|
||||
import SessionProviderLogo from '../../../SessionProviderLogo';
|
||||
import type { AppTab, Project, ProjectSession } from '../../../../types/app';
|
||||
|
||||
type MainContentTitleProps = {
|
||||
activeTab: AppTab;
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MobileMenuButtonProps } from './types';
|
||||
import { useMobileMenuHandlers } from '../../hooks/main-content/useMobileMenuHandlers';
|
||||
import type { MobileMenuButtonProps } from '../../types/types';
|
||||
import { useMobileMenuHandlers } from '../../hooks/useMobileMenuHandlers';
|
||||
|
||||
export default function MobileMenuButton({ onMenuClick, compact = false }: MobileMenuButtonProps) {
|
||||
const { handleMobileMenuClick, handleMobileMenuTouchEnd } = useMobileMenuHandlers(onMenuClick);
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import TaskList from '../TaskList';
|
||||
import TaskDetail from '../TaskDetail';
|
||||
import PRDEditor from '../PRDEditor';
|
||||
import { useTaskMaster } from '../../contexts/TaskMasterContext';
|
||||
import { api } from '../../utils/api';
|
||||
import type { Project } from '../../types/app';
|
||||
import type { PrdFile, TaskMasterPanelProps, TaskMasterTask, TaskSelection } from './types';
|
||||
import TaskList from '../../../TaskList';
|
||||
import TaskDetail from '../../../TaskDetail';
|
||||
import PRDEditor from '../../../PRDEditor';
|
||||
import { useTaskMaster } from '../../../../contexts/TaskMasterContext';
|
||||
import { api } from '../../../../utils/api';
|
||||
import type { Project } from '../../../../types/app';
|
||||
import type { PrdFile, TaskMasterPanelProps, TaskMasterTask, TaskSelection } from '../../types/types';
|
||||
|
||||
const AnyTaskList = TaskList as any;
|
||||
const AnyTaskDetail = TaskDetail as any;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type React from 'react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { api } from '../utils/api';
|
||||
import type { Project, ProjectSession } from '../types/app';
|
||||
import { api } from '../../../utils/api';
|
||||
import type { Project, ProjectSession } from '../../../types/app';
|
||||
import type {
|
||||
AdditionalSessionsByProject,
|
||||
DeleteProjectConfirmation,
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
ProjectSortOrder,
|
||||
SessionDeleteConfirmation,
|
||||
SessionWithProvider,
|
||||
} from '../components/sidebar/types';
|
||||
} from '../types/types';
|
||||
import {
|
||||
filterProjects,
|
||||
getAllSessions,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
persistStarredProjects,
|
||||
readProjectSortOrder,
|
||||
sortProjects,
|
||||
} from '../components/sidebar/utils';
|
||||
} from '../utils/utils';
|
||||
|
||||
type UseSidebarControllerArgs = {
|
||||
projects: Project[];
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { Project } from '../../types/app';
|
||||
import type { Project } from '../../../types/app';
|
||||
import type {
|
||||
AdditionalSessionsByProject,
|
||||
ProjectSortOrder,
|
||||
SessionViewModel,
|
||||
SessionWithProvider,
|
||||
} from './types';
|
||||
} from '../types/types';
|
||||
|
||||
export const readProjectSortOrder = (): ProjectSortOrder => {
|
||||
try {
|
||||
@@ -1,17 +1,17 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDeviceSettings } from '../hooks/useDeviceSettings';
|
||||
import { useVersionCheck } from '../hooks/useVersionCheck';
|
||||
import { useUiPreferences } from '../hooks/useUiPreferences';
|
||||
import { useDeviceSettings } from '../../../hooks/useDeviceSettings';
|
||||
import { useVersionCheck } from '../../../hooks/useVersionCheck';
|
||||
import { useUiPreferences } from '../../../hooks/useUiPreferences';
|
||||
import { useSidebarController } from '../hooks/useSidebarController';
|
||||
import { useTaskMaster } from '../contexts/TaskMasterContext';
|
||||
import { useTasksSettings } from '../contexts/TasksSettingsContext';
|
||||
import SidebarCollapsed from './sidebar/SidebarCollapsed';
|
||||
import SidebarContent from './sidebar/SidebarContent';
|
||||
import SidebarModals from './sidebar/SidebarModals';
|
||||
import type { Project } from '../types/app';
|
||||
import type { SidebarProjectListProps } from './sidebar/SidebarProjectList';
|
||||
import type { MCPServerStatus, SidebarProps } from './sidebar/types';
|
||||
import { useTaskMaster } from '../../../contexts/TaskMasterContext';
|
||||
import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
|
||||
import SidebarCollapsed from './subcomponents/SidebarCollapsed';
|
||||
import SidebarContent from './subcomponents/SidebarContent';
|
||||
import SidebarModals from './subcomponents/SidebarModals';
|
||||
import type { Project } from '../../../types/app';
|
||||
import type { SidebarProjectListProps } from './subcomponents/SidebarProjectList';
|
||||
import type { MCPServerStatus, SidebarProps } from '../types/types';
|
||||
|
||||
type TaskMasterSidebarContext = {
|
||||
setCurrentProject: (project: Project) => void;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ScrollArea } from '../ui/scroll-area';
|
||||
import { ScrollArea } from '../../../ui/scroll-area';
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { Project } from '../../types/app';
|
||||
import type { ReleaseInfo } from '../../types/sharedTypes';
|
||||
import type { Project } from '../../../../types/app';
|
||||
import type { ReleaseInfo } from '../../../../types/sharedTypes';
|
||||
import SidebarFooter from './SidebarFooter';
|
||||
import SidebarHeader from './SidebarHeader';
|
||||
import SidebarProjectList, { type SidebarProjectListProps } from './SidebarProjectList';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Settings } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { ReleaseInfo } from '../../types/sharedTypes';
|
||||
import { Button } from '../ui/button';
|
||||
import type { ReleaseInfo } from '../../../../types/sharedTypes';
|
||||
import { Button } from '../../../ui/button';
|
||||
|
||||
type SidebarFooterProps = {
|
||||
updateAvailable: boolean;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FolderPlus, MessageSquare, RefreshCw, Search, X } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { Button } from '../ui/button';
|
||||
import { Input } from '../ui/input';
|
||||
import { IS_PLATFORM } from '../../constants/config';
|
||||
import { Button } from '../../../ui/button';
|
||||
import { Input } from '../../../ui/input';
|
||||
import { IS_PLATFORM } from '../../../../constants/config';
|
||||
|
||||
type SidebarHeaderProps = {
|
||||
isPWA: boolean;
|
||||
@@ -1,13 +1,13 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
import { AlertTriangle, Trash2 } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { Button } from '../ui/button';
|
||||
import ProjectCreationWizard from '../ProjectCreationWizard';
|
||||
import Settings from '../Settings';
|
||||
import VersionUpgradeModal from '../modals/VersionUpgradeModal';
|
||||
import type { Project } from '../../types/app';
|
||||
import type { ReleaseInfo } from '../../types/sharedTypes';
|
||||
import type { DeleteProjectConfirmation, SessionDeleteConfirmation } from './types';
|
||||
import { Button } from '../../../ui/button';
|
||||
import ProjectCreationWizard from '../../../ProjectCreationWizard';
|
||||
import Settings from '../../../Settings';
|
||||
import VersionUpgradeModal from '../../../modals/VersionUpgradeModal';
|
||||
import type { Project } from '../../../../types/app';
|
||||
import type { ReleaseInfo } from '../../../../types/sharedTypes';
|
||||
import type { DeleteProjectConfirmation, SessionDeleteConfirmation } from '../../types/types';
|
||||
|
||||
type SidebarModalsProps = {
|
||||
projects: Project[];
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Button } from '../ui/button';
|
||||
import { Button } from '../../../ui/button';
|
||||
import { Check, ChevronDown, ChevronRight, Edit3, Folder, FolderOpen, Star, Trash2, X } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { cn } from '../../lib/utils';
|
||||
import TaskIndicator from '../TaskIndicator';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../types/app';
|
||||
import type { MCPServerStatus, SessionWithProvider, TouchHandlerFactory } from './types';
|
||||
import { getTaskIndicatorStatus } from './utils';
|
||||
import { cn } from '../../../../lib/utils';
|
||||
import TaskIndicator from '../../../TaskIndicator';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
|
||||
import type { MCPServerStatus, SessionWithProvider, TouchHandlerFactory } from '../../types/types';
|
||||
import { getTaskIndicatorStatus } from '../../utils/utils';
|
||||
import SidebarProjectSessions from './SidebarProjectSessions';
|
||||
|
||||
type SidebarProjectItemProps = {
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { LoadingProgress, Project, ProjectSession, SessionProvider } from '../../types/app';
|
||||
import type { LoadingProgress, Project, ProjectSession, SessionProvider } from '../../../../types/app';
|
||||
import type {
|
||||
LoadingSessionsByProject,
|
||||
MCPServerStatus,
|
||||
SessionWithProvider,
|
||||
TouchHandlerFactory,
|
||||
} from './types';
|
||||
} from '../../types/types';
|
||||
import SidebarProjectItem from './SidebarProjectItem';
|
||||
import SidebarProjectsState from './SidebarProjectsState';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ChevronDown, Plus } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { Button } from '../ui/button';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../types/app';
|
||||
import type { SessionWithProvider, TouchHandlerFactory } from './types';
|
||||
import { Button } from '../../../ui/button';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
|
||||
import type { SessionWithProvider, TouchHandlerFactory } from '../../types/types';
|
||||
import SidebarSessionItem from './SidebarSessionItem';
|
||||
|
||||
type SidebarProjectSessionsProps = {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Folder, Search } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { LoadingProgress } from '../../types/app';
|
||||
import type { LoadingProgress } from '../../../../types/app';
|
||||
|
||||
type SidebarProjectsStateProps = {
|
||||
isLoading: boolean;
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Badge } from '../ui/badge';
|
||||
import { Button } from '../ui/button';
|
||||
import { Badge } from '../../../ui/badge';
|
||||
import { Button } from '../../../ui/button';
|
||||
import { Check, Clock, Edit2, Trash2, X } from 'lucide-react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { cn } from '../../lib/utils';
|
||||
import { formatTimeAgo } from '../../utils/dateUtils';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../types/app';
|
||||
import type { SessionWithProvider, TouchHandlerFactory } from './types';
|
||||
import { createSessionViewModel } from './utils';
|
||||
import SessionProviderLogo from '../SessionProviderLogo';
|
||||
import { cn } from '../../../../lib/utils';
|
||||
import { formatTimeAgo } from '../../../../utils/dateUtils';
|
||||
import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
|
||||
import type { SessionWithProvider, TouchHandlerFactory } from '../../types/types';
|
||||
import { createSessionViewModel } from '../../utils/utils';
|
||||
import SessionProviderLogo from '../../../SessionProviderLogo';
|
||||
|
||||
type SidebarSessionItemProps = {
|
||||
project: Project;
|
||||
@@ -1,109 +0,0 @@
|
||||
import { useState, useRef, useCallback } from 'react';
|
||||
|
||||
export function useAudioRecorder() {
|
||||
const [isRecording, setRecording] = useState(false);
|
||||
const [audioBlob, setAudioBlob] = useState(null);
|
||||
const [error, setError] = useState(null);
|
||||
const mediaRecorderRef = useRef(null);
|
||||
const streamRef = useRef(null);
|
||||
const chunksRef = useRef([]);
|
||||
|
||||
const start = useCallback(async () => {
|
||||
try {
|
||||
setError(null);
|
||||
setAudioBlob(null);
|
||||
chunksRef.current = [];
|
||||
|
||||
// Request microphone access
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
sampleRate: 16000,
|
||||
}
|
||||
});
|
||||
|
||||
streamRef.current = stream;
|
||||
|
||||
// Determine supported MIME type
|
||||
const mimeType = MediaRecorder.isTypeSupported('audio/webm')
|
||||
? 'audio/webm'
|
||||
: 'audio/mp4';
|
||||
|
||||
// Create media recorder
|
||||
const recorder = new MediaRecorder(stream, { mimeType });
|
||||
mediaRecorderRef.current = recorder;
|
||||
|
||||
// Set up event handlers
|
||||
recorder.ondataavailable = (e) => {
|
||||
if (e.data.size > 0) {
|
||||
chunksRef.current.push(e.data);
|
||||
}
|
||||
};
|
||||
|
||||
recorder.onstop = () => {
|
||||
// Create blob from chunks
|
||||
const blob = new Blob(chunksRef.current, { type: mimeType });
|
||||
setAudioBlob(blob);
|
||||
|
||||
// Clean up stream
|
||||
if (streamRef.current) {
|
||||
streamRef.current.getTracks().forEach(track => track.stop());
|
||||
streamRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
recorder.onerror = (event) => {
|
||||
console.error('MediaRecorder error:', event);
|
||||
setError('Recording failed');
|
||||
setRecording(false);
|
||||
};
|
||||
|
||||
// Start recording
|
||||
recorder.start();
|
||||
setRecording(true);
|
||||
console.log('Recording started');
|
||||
} catch (err) {
|
||||
console.error('Failed to start recording:', err);
|
||||
setError(err.message || 'Failed to start recording');
|
||||
setRecording(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const stop = useCallback(() => {
|
||||
console.log('Stop called, recorder state:', mediaRecorderRef.current?.state);
|
||||
|
||||
try {
|
||||
if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') {
|
||||
mediaRecorderRef.current.stop();
|
||||
console.log('Recording stopped');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error stopping recorder:', err);
|
||||
}
|
||||
|
||||
// Always update state
|
||||
setRecording(false);
|
||||
|
||||
// Clean up stream if still active
|
||||
if (streamRef.current) {
|
||||
streamRef.current.getTracks().forEach(track => track.stop());
|
||||
streamRef.current = null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setAudioBlob(null);
|
||||
setError(null);
|
||||
chunksRef.current = [];
|
||||
}, []);
|
||||
|
||||
return {
|
||||
isRecording,
|
||||
audioBlob,
|
||||
error,
|
||||
start,
|
||||
stop,
|
||||
reset
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user