refactor: Restructure files and folders to better mimic feature-based architecture

This commit is contained in:
Haileyesus
2026-02-11 18:11:06 +03:00
parent fadbcc8259
commit 7f45540dbe
34 changed files with 124 additions and 233 deletions

View File

@@ -2,8 +2,8 @@ import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Sidebar from '../Sidebar'; import Sidebar from '../sidebar/view/Sidebar';
import MainContent from '../MainContent'; import MainContent from '../main-content/view/MainContent';
import MobileNav from '../MobileNav'; import MobileNav from '../MobileNav';
import { useWebSocket } from '../../contexts/WebSocketContext'; import { useWebSocket } from '../../contexts/WebSocketContext';

View File

@@ -10,19 +10,19 @@ import type {
TouchEvent, TouchEvent,
} from 'react'; } from 'react';
import { useDropzone } from 'react-dropzone'; import { useDropzone } from 'react-dropzone';
import { authenticatedFetch } from '../../utils/api'; import { authenticatedFetch } from '../../../utils/api';
import { thinkingModes } from '../../components/ThinkingModeSelector.jsx'; import { thinkingModes } from '../../ThinkingModeSelector.jsx';
import { grantClaudeToolPermission } from '../../components/chat/utils/chatPermissions'; import { grantClaudeToolPermission } from '../utils/chatPermissions';
import { safeLocalStorage } from '../../components/chat/utils/chatStorage'; import { safeLocalStorage } from '../utils/chatStorage';
import type { import type {
ChatMessage, ChatMessage,
PendingPermissionRequest, PendingPermissionRequest,
PermissionMode, PermissionMode,
Provider, Provider,
} from '../../components/chat/types'; } from '../types';
import { useFileMentions } from './useFileMentions'; import { useFileMentions } from './useFileMentions';
import { type SlashCommand, useSlashCommands } from './useSlashCommands'; import { type SlashCommand, useSlashCommands } from './useSlashCommands';
import type { Project, ProjectSession } from '../../types/app'; import type { Project, ProjectSession } from '../../../types/app';
type PendingViewSession = { type PendingViewSession = {
sessionId: string | null; sessionId: string | null;

View File

@@ -1,8 +1,8 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { authenticatedFetch } from '../../utils/api'; import { authenticatedFetch } from '../../../utils/api';
import { CLAUDE_MODELS, CODEX_MODELS, CURSOR_MODELS } from '../../../shared/modelConstants'; import { CLAUDE_MODELS, CODEX_MODELS, CURSOR_MODELS } from '../../../../shared/modelConstants';
import type { PendingPermissionRequest, PermissionMode, Provider } from '../../components/chat/types'; import type { PendingPermissionRequest, PermissionMode, Provider } from '../types';
import type { ProjectSession } from '../../types/app'; import type { ProjectSession } from '../../../types/app';
interface UseChatProviderStateArgs { interface UseChatProviderStateArgs {
selectedSession: ProjectSession | null; selectedSession: ProjectSession | null;

View File

@@ -1,9 +1,9 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import type { Dispatch, MutableRefObject, SetStateAction } from 'react'; import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
import { decodeHtmlEntities, formatUsageLimitText } from '../../components/chat/utils/chatFormatting'; import { decodeHtmlEntities, formatUsageLimitText } from '../utils/chatFormatting';
import { safeLocalStorage } from '../../components/chat/utils/chatStorage'; import { safeLocalStorage } from '../utils/chatStorage';
import type { ChatMessage, PendingPermissionRequest, Provider } from '../../components/chat/types'; import type { ChatMessage, PendingPermissionRequest, Provider } from '../types';
import type { Project, ProjectSession } from '../../types/app'; import type { Project, ProjectSession } from '../../../types/app';
type PendingViewSession = { type PendingViewSession = {
sessionId: string | null; sessionId: string | null;

View File

@@ -1,15 +1,15 @@
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import { api, authenticatedFetch } from '../../utils/api'; import { api, authenticatedFetch } from '../../../utils/api';
import type { ChatMessage, Provider } from '../../components/chat/types'; import type { ChatMessage, Provider } from '../types';
import type { Project, ProjectSession } from '../../types/app'; import type { Project, ProjectSession } from '../../../types/app';
import { safeLocalStorage } from '../../components/chat/utils/chatStorage'; import { safeLocalStorage } from '../utils/chatStorage';
import { import {
convertCursorSessionMessages, convertCursorSessionMessages,
convertSessionMessages, convertSessionMessages,
createCachedDiffCalculator, createCachedDiffCalculator,
type DiffCalculator, type DiffCalculator,
} from '../../components/chat/utils/messageTransforms'; } from '../utils/messageTransforms';
const MESSAGES_PER_PAGE = 20; const MESSAGES_PER_PAGE = 20;
const INITIAL_VISIBLE_MESSAGES = 100; const INITIAL_VISIBLE_MESSAGES = 100;

View File

@@ -1,8 +1,8 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react'; import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react';
import { api } from '../../utils/api'; import { api } from '../../../utils/api';
import { escapeRegExp } from '../../components/chat/utils/chatFormatting'; import { escapeRegExp } from '../utils/chatFormatting';
import type { Project } from '../../types/app'; import type { Project } from '../../../types/app';
interface ProjectFileNode { interface ProjectFileNode {
name: string; name: string;

View File

@@ -1,9 +1,9 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react'; import type { Dispatch, KeyboardEvent, RefObject, SetStateAction } from 'react';
import Fuse from 'fuse.js'; import Fuse from 'fuse.js';
import { authenticatedFetch } from '../../utils/api'; import { authenticatedFetch } from '../../../utils/api';
import { safeLocalStorage } from '../../components/chat/utils/chatStorage'; import { safeLocalStorage } from '../utils/chatStorage';
import type { Project } from '../../types/app'; import type { Project } from '../../../types/app';
const COMMAND_QUERY_DEBOUNCE_MS = 150; const COMMAND_QUERY_DEBOUNCE_MS = 150;

View File

@@ -1,15 +1,15 @@
import React, { useCallback, useEffect, useRef } from 'react'; import React, { useCallback, useEffect, useRef } from 'react';
import QuickSettingsPanel from './QuickSettingsPanel'; import QuickSettingsPanel from '../../QuickSettingsPanel';
import { useTasksSettings } from '../contexts/TasksSettingsContext'; import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ChatMessagesPane from './chat/view/ChatMessagesPane'; import ChatMessagesPane from './ChatMessagesPane';
import ChatComposer from './chat/view/ChatComposer'; import ChatComposer from './ChatComposer';
import type { ChatInterfaceProps } from './chat/types'; import type { ChatInterfaceProps } from '../types';
import { useChatProviderState } from '../hooks/chat/useChatProviderState'; import { useChatProviderState } from '../hooks/useChatProviderState';
import { useChatSessionState } from '../hooks/chat/useChatSessionState'; import { useChatSessionState } from '../hooks/useChatSessionState';
import { useChatRealtimeHandlers } from '../hooks/chat/useChatRealtimeHandlers'; import { useChatRealtimeHandlers } from '../hooks/useChatRealtimeHandlers';
import { useChatComposerState } from '../hooks/chat/useChatComposerState'; import { useChatComposerState } from '../hooks/useChatComposerState';
import type { Provider } from './chat/types'; import type { Provider } from '../types';
type PendingViewSession = { type PendingViewSession = {
sessionId: string | null; sessionId: string | null;

View File

@@ -1,7 +1,7 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import type { MouseEvent as ReactMouseEvent } from 'react'; import type { MouseEvent as ReactMouseEvent } from 'react';
import type { Project } from '../../types/app'; import type { Project } from '../../../types/app';
import type { DiffInfo, EditingFile } from '../../components/main-content/types'; import type { DiffInfo, EditingFile } from '../types/types';
type UseEditorSidebarOptions = { type UseEditorSidebarOptions = {
selectedProject: Project | null; selectedProject: Project | null;

View File

@@ -1,5 +1,5 @@
import type { Dispatch, MouseEvent, RefObject, SetStateAction } from 'react'; 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; export type SessionLifecycleHandler = (sessionId?: string | null) => void;

View File

@@ -1,22 +1,22 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import ChatInterface from './ChatInterface'; import ChatInterface from '../../chat/view/ChatInterface';
import FileTree from './FileTree'; import FileTree from '../../FileTree';
import StandaloneShell from './StandaloneShell'; import StandaloneShell from '../../StandaloneShell';
import GitPanel from './GitPanel'; import GitPanel from '../../GitPanel';
import ErrorBoundary from './ErrorBoundary'; import ErrorBoundary from '../../ErrorBoundary';
import MainContentHeader from './main-content/MainContentHeader'; import MainContentHeader from './subcomponents/MainContentHeader';
import MainContentStateView from './main-content/MainContentStateView'; import MainContentStateView from './subcomponents/MainContentStateView';
import EditorSidebar from './main-content/EditorSidebar'; import EditorSidebar from './subcomponents/EditorSidebar';
import TaskMasterPanel from './main-content/TaskMasterPanel'; import TaskMasterPanel from './subcomponents/TaskMasterPanel';
import type { MainContentProps } from './main-content/types'; import type { MainContentProps } from '../types/types';
import { useTaskMaster } from '../contexts/TaskMasterContext'; import { useTaskMaster } from '../../../contexts/TaskMasterContext';
import { useTasksSettings } from '../contexts/TasksSettingsContext'; import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
import { useUiPreferences } from '../hooks/useUiPreferences'; import { useUiPreferences } from '../../../hooks/useUiPreferences';
import { useEditorSidebar } from '../hooks/main-content/useEditorSidebar'; import { useEditorSidebar } from '../hooks/useEditorSidebar';
import type { Project } from '../types/app'; import type { Project } from '../../../types/app';
const AnyStandaloneShell = StandaloneShell as any; const AnyStandaloneShell = StandaloneShell as any;
const AnyGitPanel = GitPanel as any; const AnyGitPanel = GitPanel as any;

View File

@@ -1,5 +1,5 @@
import CodeEditor from '../CodeEditor'; import CodeEditor from '../../../CodeEditor';
import type { EditorSidebarProps } from './types'; import type { EditorSidebarProps } from '../../types/types';
const AnyCodeEditor = CodeEditor as any; const AnyCodeEditor = CodeEditor as any;

View File

@@ -1,7 +1,7 @@
import MobileMenuButton from './MobileMenuButton'; import MobileMenuButton from './MobileMenuButton';
import MainContentTabSwitcher from './MainContentTabSwitcher'; import MainContentTabSwitcher from './MainContentTabSwitcher';
import MainContentTitle from './MainContentTitle'; import MainContentTitle from './MainContentTitle';
import type { MainContentHeaderProps } from './types'; import type { MainContentHeaderProps } from '../../types/types';
export default function MainContentHeader({ export default function MainContentHeader({
activeTab, activeTab,

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import MobileMenuButton from './MobileMenuButton'; import MobileMenuButton from './MobileMenuButton';
import type { MainContentStateViewProps } from './types'; import type { MainContentStateViewProps } from '../../types/types';
export default function MainContentStateView({ mode, isMobile, onMenuClick }: MainContentStateViewProps) { export default function MainContentStateView({ mode, isMobile, onMenuClick }: MainContentStateViewProps) {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -1,5 +1,5 @@
import Tooltip from '../Tooltip'; import Tooltip from '../../../Tooltip';
import type { AppTab } from '../../types/app'; import type { AppTab } from '../../../../types/app';
import type { Dispatch, SetStateAction } from 'react'; import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import SessionProviderLogo from '../SessionProviderLogo'; import SessionProviderLogo from '../../../SessionProviderLogo';
import type { AppTab, Project, ProjectSession } from '../../types/app'; import type { AppTab, Project, ProjectSession } from '../../../../types/app';
type MainContentTitleProps = { type MainContentTitleProps = {
activeTab: AppTab; activeTab: AppTab;

View File

@@ -1,5 +1,5 @@
import type { MobileMenuButtonProps } from './types'; import type { MobileMenuButtonProps } from '../../types/types';
import { useMobileMenuHandlers } from '../../hooks/main-content/useMobileMenuHandlers'; import { useMobileMenuHandlers } from '../../hooks/useMobileMenuHandlers';
export default function MobileMenuButton({ onMenuClick, compact = false }: MobileMenuButtonProps) { export default function MobileMenuButton({ onMenuClick, compact = false }: MobileMenuButtonProps) {
const { handleMobileMenuClick, handleMobileMenuTouchEnd } = useMobileMenuHandlers(onMenuClick); const { handleMobileMenuClick, handleMobileMenuTouchEnd } = useMobileMenuHandlers(onMenuClick);

View File

@@ -1,11 +1,11 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import TaskList from '../TaskList'; import TaskList from '../../../TaskList';
import TaskDetail from '../TaskDetail'; import TaskDetail from '../../../TaskDetail';
import PRDEditor from '../PRDEditor'; import PRDEditor from '../../../PRDEditor';
import { useTaskMaster } from '../../contexts/TaskMasterContext'; import { useTaskMaster } from '../../../../contexts/TaskMasterContext';
import { api } from '../../utils/api'; import { api } from '../../../../utils/api';
import type { Project } from '../../types/app'; import type { Project } from '../../../../types/app';
import type { PrdFile, TaskMasterPanelProps, TaskMasterTask, TaskSelection } from './types'; import type { PrdFile, TaskMasterPanelProps, TaskMasterTask, TaskSelection } from '../../types/types';
const AnyTaskList = TaskList as any; const AnyTaskList = TaskList as any;
const AnyTaskDetail = TaskDetail as any; const AnyTaskDetail = TaskDetail as any;

View File

@@ -1,8 +1,8 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import type React from 'react'; import type React from 'react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { api } from '../utils/api'; import { api } from '../../../utils/api';
import type { Project, ProjectSession } from '../types/app'; import type { Project, ProjectSession } from '../../../types/app';
import type { import type {
AdditionalSessionsByProject, AdditionalSessionsByProject,
DeleteProjectConfirmation, DeleteProjectConfirmation,
@@ -10,7 +10,7 @@ import type {
ProjectSortOrder, ProjectSortOrder,
SessionDeleteConfirmation, SessionDeleteConfirmation,
SessionWithProvider, SessionWithProvider,
} from '../components/sidebar/types'; } from '../types/types';
import { import {
filterProjects, filterProjects,
getAllSessions, getAllSessions,
@@ -18,7 +18,7 @@ import {
persistStarredProjects, persistStarredProjects,
readProjectSortOrder, readProjectSortOrder,
sortProjects, sortProjects,
} from '../components/sidebar/utils'; } from '../utils/utils';
type UseSidebarControllerArgs = { type UseSidebarControllerArgs = {
projects: Project[]; projects: Project[];

View File

@@ -1,11 +1,11 @@
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { Project } from '../../types/app'; import type { Project } from '../../../types/app';
import type { import type {
AdditionalSessionsByProject, AdditionalSessionsByProject,
ProjectSortOrder, ProjectSortOrder,
SessionViewModel, SessionViewModel,
SessionWithProvider, SessionWithProvider,
} from './types'; } from '../types/types';
export const readProjectSortOrder = (): ProjectSortOrder => { export const readProjectSortOrder = (): ProjectSortOrder => {
try { try {

View File

@@ -1,17 +1,17 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDeviceSettings } from '../hooks/useDeviceSettings'; import { useDeviceSettings } from '../../../hooks/useDeviceSettings';
import { useVersionCheck } from '../hooks/useVersionCheck'; import { useVersionCheck } from '../../../hooks/useVersionCheck';
import { useUiPreferences } from '../hooks/useUiPreferences'; import { useUiPreferences } from '../../../hooks/useUiPreferences';
import { useSidebarController } from '../hooks/useSidebarController'; import { useSidebarController } from '../hooks/useSidebarController';
import { useTaskMaster } from '../contexts/TaskMasterContext'; import { useTaskMaster } from '../../../contexts/TaskMasterContext';
import { useTasksSettings } from '../contexts/TasksSettingsContext'; import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
import SidebarCollapsed from './sidebar/SidebarCollapsed'; import SidebarCollapsed from './subcomponents/SidebarCollapsed';
import SidebarContent from './sidebar/SidebarContent'; import SidebarContent from './subcomponents/SidebarContent';
import SidebarModals from './sidebar/SidebarModals'; import SidebarModals from './subcomponents/SidebarModals';
import type { Project } from '../types/app'; import type { Project } from '../../../types/app';
import type { SidebarProjectListProps } from './sidebar/SidebarProjectList'; import type { SidebarProjectListProps } from './subcomponents/SidebarProjectList';
import type { MCPServerStatus, SidebarProps } from './sidebar/types'; import type { MCPServerStatus, SidebarProps } from '../types/types';
type TaskMasterSidebarContext = { type TaskMasterSidebarContext = {
setCurrentProject: (project: Project) => void; setCurrentProject: (project: Project) => void;

View File

@@ -1,7 +1,7 @@
import { ScrollArea } from '../ui/scroll-area'; import { ScrollArea } from '../../../ui/scroll-area';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { Project } from '../../types/app'; import type { Project } from '../../../../types/app';
import type { ReleaseInfo } from '../../types/sharedTypes'; import type { ReleaseInfo } from '../../../../types/sharedTypes';
import SidebarFooter from './SidebarFooter'; import SidebarFooter from './SidebarFooter';
import SidebarHeader from './SidebarHeader'; import SidebarHeader from './SidebarHeader';
import SidebarProjectList, { type SidebarProjectListProps } from './SidebarProjectList'; import SidebarProjectList, { type SidebarProjectListProps } from './SidebarProjectList';

View File

@@ -1,7 +1,7 @@
import { Settings } from 'lucide-react'; import { Settings } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { ReleaseInfo } from '../../types/sharedTypes'; import type { ReleaseInfo } from '../../../../types/sharedTypes';
import { Button } from '../ui/button'; import { Button } from '../../../ui/button';
type SidebarFooterProps = { type SidebarFooterProps = {
updateAvailable: boolean; updateAvailable: boolean;

View File

@@ -1,8 +1,8 @@
import { FolderPlus, MessageSquare, RefreshCw, Search, X } from 'lucide-react'; import { FolderPlus, MessageSquare, RefreshCw, Search, X } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { Button } from '../ui/button'; import { Button } from '../../../ui/button';
import { Input } from '../ui/input'; import { Input } from '../../../ui/input';
import { IS_PLATFORM } from '../../constants/config'; import { IS_PLATFORM } from '../../../../constants/config';
type SidebarHeaderProps = { type SidebarHeaderProps = {
isPWA: boolean; isPWA: boolean;

View File

@@ -1,13 +1,13 @@
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { AlertTriangle, Trash2 } from 'lucide-react'; import { AlertTriangle, Trash2 } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { Button } from '../ui/button'; import { Button } from '../../../ui/button';
import ProjectCreationWizard from '../ProjectCreationWizard'; import ProjectCreationWizard from '../../../ProjectCreationWizard';
import Settings from '../Settings'; import Settings from '../../../Settings';
import VersionUpgradeModal from '../modals/VersionUpgradeModal'; import VersionUpgradeModal from '../../../modals/VersionUpgradeModal';
import type { Project } from '../../types/app'; import type { Project } from '../../../../types/app';
import type { ReleaseInfo } from '../../types/sharedTypes'; import type { ReleaseInfo } from '../../../../types/sharedTypes';
import type { DeleteProjectConfirmation, SessionDeleteConfirmation } from './types'; import type { DeleteProjectConfirmation, SessionDeleteConfirmation } from '../../types/types';
type SidebarModalsProps = { type SidebarModalsProps = {
projects: Project[]; projects: Project[];

View File

@@ -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 { Check, ChevronDown, ChevronRight, Edit3, Folder, FolderOpen, Star, Trash2, X } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { cn } from '../../lib/utils'; import { cn } from '../../../../lib/utils';
import TaskIndicator from '../TaskIndicator'; import TaskIndicator from '../../../TaskIndicator';
import type { Project, ProjectSession, SessionProvider } from '../../types/app'; import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
import type { MCPServerStatus, SessionWithProvider, TouchHandlerFactory } from './types'; import type { MCPServerStatus, SessionWithProvider, TouchHandlerFactory } from '../../types/types';
import { getTaskIndicatorStatus } from './utils'; import { getTaskIndicatorStatus } from '../../utils/utils';
import SidebarProjectSessions from './SidebarProjectSessions'; import SidebarProjectSessions from './SidebarProjectSessions';
type SidebarProjectItemProps = { type SidebarProjectItemProps = {

View File

@@ -1,11 +1,11 @@
import type { TFunction } from 'i18next'; 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 { import type {
LoadingSessionsByProject, LoadingSessionsByProject,
MCPServerStatus, MCPServerStatus,
SessionWithProvider, SessionWithProvider,
TouchHandlerFactory, TouchHandlerFactory,
} from './types'; } from '../../types/types';
import SidebarProjectItem from './SidebarProjectItem'; import SidebarProjectItem from './SidebarProjectItem';
import SidebarProjectsState from './SidebarProjectsState'; import SidebarProjectsState from './SidebarProjectsState';

View File

@@ -1,8 +1,8 @@
import { ChevronDown, Plus } from 'lucide-react'; import { ChevronDown, Plus } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { Button } from '../ui/button'; import { Button } from '../../../ui/button';
import type { Project, ProjectSession, SessionProvider } from '../../types/app'; import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
import type { SessionWithProvider, TouchHandlerFactory } from './types'; import type { SessionWithProvider, TouchHandlerFactory } from '../../types/types';
import SidebarSessionItem from './SidebarSessionItem'; import SidebarSessionItem from './SidebarSessionItem';
type SidebarProjectSessionsProps = { type SidebarProjectSessionsProps = {

View File

@@ -1,6 +1,6 @@
import { Folder, Search } from 'lucide-react'; import { Folder, Search } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { LoadingProgress } from '../../types/app'; import type { LoadingProgress } from '../../../../types/app';
type SidebarProjectsStateProps = { type SidebarProjectsStateProps = {
isLoading: boolean; isLoading: boolean;

View File

@@ -1,13 +1,13 @@
import { Badge } from '../ui/badge'; import { Badge } from '../../../ui/badge';
import { Button } from '../ui/button'; import { Button } from '../../../ui/button';
import { Check, Clock, Edit2, Trash2, X } from 'lucide-react'; import { Check, Clock, Edit2, Trash2, X } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { cn } from '../../lib/utils'; import { cn } from '../../../../lib/utils';
import { formatTimeAgo } from '../../utils/dateUtils'; import { formatTimeAgo } from '../../../../utils/dateUtils';
import type { Project, ProjectSession, SessionProvider } from '../../types/app'; import type { Project, ProjectSession, SessionProvider } from '../../../../types/app';
import type { SessionWithProvider, TouchHandlerFactory } from './types'; import type { SessionWithProvider, TouchHandlerFactory } from '../../types/types';
import { createSessionViewModel } from './utils'; import { createSessionViewModel } from '../../utils/utils';
import SessionProviderLogo from '../SessionProviderLogo'; import SessionProviderLogo from '../../../SessionProviderLogo';
type SidebarSessionItemProps = { type SidebarSessionItemProps = {
project: Project; project: Project;

View File

@@ -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
};
}