Files
claude-task-master/apps/extension/src/webview/reducers/appReducer.ts
DavidMaliglowka 64302dc191 feat(extension): complete VS Code extension with kanban board interface (#997)
---------
Co-authored-by: DavidMaliglowka <13022280+DavidMaliglowka@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-01 14:04:22 +02:00

193 lines
4.9 KiB
TypeScript

/**
* Main application state reducer
*/
import type { AppState, AppAction } from '../types';
import { logger } from '../utils/logger';
export const appReducer = (state: AppState, action: AppAction): AppState => {
logger.debug(
'Reducer action:',
action.type,
'payload' in action ? action.payload : 'no payload'
);
switch (action.type) {
case 'SET_TASKS':
const newTasks = Array.isArray(action.payload) ? action.payload : [];
logger.debug('SET_TASKS reducer - updating tasks:', {
oldCount: state.tasks.length,
newCount: newTasks.length,
newTasks
});
return {
...state,
tasks: newTasks,
loading: false,
error: undefined
};
case 'SET_LOADING':
return { ...state, loading: action.payload };
case 'SET_ERROR':
return { ...state, error: action.payload, loading: false };
case 'CLEAR_ERROR':
return { ...state, error: undefined };
case 'INCREMENT_REQUEST_ID':
return { ...state, requestId: state.requestId + 1 };
case 'UPDATE_TASK_STATUS': {
const { taskId, newStatus } = action.payload;
return {
...state,
tasks: state.tasks.map((task) =>
task.id === taskId ? { ...task, status: newStatus } : task
)
};
}
case 'UPDATE_TASK_CONTENT': {
const { taskId, updates } = action.payload;
return {
...state,
tasks: state.tasks.map((task) =>
task.id === taskId ? { ...task, ...updates } : task
)
};
}
case 'SET_CONNECTION_STATUS':
return {
...state,
isConnected: action.payload.isConnected,
connectionStatus: action.payload.status
};
case 'SET_EDITING_TASK':
return {
...state,
editingTask: action.payload
};
case 'SET_POLLING_STATUS':
return {
...state,
polling: {
...state.polling,
isActive: action.payload.isActive,
errorCount: action.payload.errorCount ?? state.polling.errorCount,
lastUpdate: action.payload.isActive
? Date.now()
: state.polling.lastUpdate
}
};
case 'SET_USER_INTERACTING':
return {
...state,
polling: {
...state.polling,
isUserInteracting: action.payload
}
};
case 'TASKS_UPDATED_FROM_POLLING':
return {
...state,
tasks: Array.isArray(action.payload) ? action.payload : [],
polling: {
...state.polling,
lastUpdate: Date.now()
}
};
case 'SET_NETWORK_STATUS':
return {
...state,
polling: {
...state.polling,
isOfflineMode: action.payload.isOfflineMode,
connectionStatus: action.payload.connectionStatus,
reconnectAttempts:
action.payload.reconnectAttempts !== undefined
? action.payload.reconnectAttempts
: state.polling.reconnectAttempts,
maxReconnectAttempts:
action.payload.maxReconnectAttempts !== undefined
? action.payload.maxReconnectAttempts
: state.polling.maxReconnectAttempts,
lastSuccessfulConnection:
action.payload.lastSuccessfulConnection !== undefined
? action.payload.lastSuccessfulConnection
: state.polling.lastSuccessfulConnection
}
};
case 'LOAD_CACHED_TASKS':
return {
...state,
tasks: Array.isArray(action.payload) ? action.payload : []
};
case 'ADD_TOAST':
return {
...state,
toastNotifications: [...state.toastNotifications, action.payload]
};
case 'REMOVE_TOAST':
return {
...state,
toastNotifications: state.toastNotifications.filter(
(notification) => notification.id !== action.payload
)
};
case 'CLEAR_ALL_TOASTS':
return { ...state, toastNotifications: [] };
case 'NAVIGATE_TO_TASK':
logger.debug('📍 Reducer: Navigating to task:', action.payload);
return {
...state,
currentView: 'task-details',
selectedTaskId: action.payload
};
case 'NAVIGATE_TO_KANBAN':
logger.debug('📍 Reducer: Navigating to kanban');
return { ...state, currentView: 'kanban', selectedTaskId: undefined };
case 'NAVIGATE_TO_CONFIG':
logger.debug('📍 Reducer: Navigating to config');
return { ...state, currentView: 'config', selectedTaskId: undefined };
case 'SET_CURRENT_TAG':
return {
...state,
currentTag: action.payload
};
case 'SET_AVAILABLE_TAGS':
return {
...state,
availableTags: action.payload
};
case 'SET_TAG_DATA':
return {
...state,
currentTag: action.payload.currentTag,
availableTags: action.payload.availableTags
};
default:
return state;
}
};
export const initialState: AppState = {
tasks: [],
loading: true,
requestId: 0,
isConnected: false,
connectionStatus: 'Connecting...',
editingTask: { taskId: null },
polling: {
isActive: false,
errorCount: 0,
lastUpdate: undefined,
isUserInteracting: false,
isOfflineMode: false,
reconnectAttempts: 0,
maxReconnectAttempts: 0,
lastSuccessfulConnection: undefined,
connectionStatus: 'online'
},
toastNotifications: [],
currentView: 'kanban',
selectedTaskId: undefined,
// Tag-related state
currentTag: 'master',
availableTags: ['master']
};