diff --git a/src/components/personal/TaskWorkspace.tsx b/src/components/personal/TaskWorkspace.tsx index 50fb457..26211e0 100644 --- a/src/components/personal/TaskWorkspace.tsx +++ b/src/components/personal/TaskWorkspace.tsx @@ -18,9 +18,10 @@ import { LearningMaterialViewer } from './LearningMaterialViewer' interface TaskWorkspaceProps { task: ChallengeTask onTaskComplete?: () => void + onTaskSkip?: () => void } -export const TaskWorkspace = ({ task, onTaskComplete }: TaskWorkspaceProps) => { +export const TaskWorkspace = ({ task, onTaskComplete, onTaskSkip }: TaskWorkspaceProps) => { const { refreshStats } = useChallenge() const { result, setResult, submit, queueStatus, finalSubmission, isSubmitting } = useSubmission({ taskId: task.id, @@ -397,7 +398,7 @@ export const TaskWorkspace = ({ task, onTaskComplete }: TaskWorkspaceProps) => { {!isAccepted && ( <> @@ -202,7 +259,7 @@ export const TaskPage = () => { - + diff --git a/src/utils/polling.ts b/src/utils/polling.ts index 5558d11..e09affe 100644 --- a/src/utils/polling.ts +++ b/src/utils/polling.ts @@ -16,7 +16,7 @@ export class PollingManager { constructor(options: PollingOptions = {}) { this.currentDelay = options.initialDelay ?? 2000 this.maxDelay = options.maxDelay ?? 10000 - this.multiplier = options.multiplier ?? 1.5 + this.multiplier = options.multiplier ?? 1.01 } async start(callback: PollCallback) { diff --git a/src/utils/storage.ts b/src/utils/storage.ts index f5cea93..10a631f 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -16,8 +16,9 @@ export const STORAGE_KEYS = { SELECTED_TASK_ID: 'challengeSelectedTaskId', } as const -// Вспомогательная функция для ключа прогресса цепочки +// Вспомогательные функции для ключей const getFurthestTaskKey = (chainId: string) => `challengeFurthestTask_${chainId}` +const getSkippedTasksKey = (chainId: string) => `challengeSkippedTasks_${chainId}` // Получение значений export const storage = { @@ -121,11 +122,11 @@ export const storage = { // Очистка всех прогрессов по цепочкам clearAllChainProgress: (): void => { if (!isBrowser()) return - // Перебираем все ключи localStorage и удаляем те, что начинаются с challengeFurthestTask_ + // Перебираем все ключи localStorage и удаляем те, что начинаются с challengeFurthestTask_ или challengeSkippedTasks_ const keysToRemove: string[] = [] for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i) - if (key && key.startsWith('challengeFurthestTask_')) { + if (key && (key.startsWith('challengeFurthestTask_') || key.startsWith('challengeSkippedTasks_'))) { keysToRemove.push(key) } } @@ -161,5 +162,43 @@ export const storage = { if (!isBrowser()) return localStorage.removeItem(getFurthestTaskKey(chainId)) }, + + // Получение пропущенных заданий для цепочки + getSkippedTasks: (chainId: string): string[] => { + if (!isBrowser()) return [] + const value = localStorage.getItem(getSkippedTasksKey(chainId)) + return value ? JSON.parse(value) : [] + }, + + // Добавление задания в список пропущенных + addSkippedTask: (chainId: string, taskId: string): void => { + if (!isBrowser()) return + const skipped = storage.getSkippedTasks(chainId) + if (!skipped.includes(taskId)) { + skipped.push(taskId) + localStorage.setItem(getSkippedTasksKey(chainId), JSON.stringify(skipped)) + } + }, + + // Удаление задания из списка пропущенных (когда оно выполнено) + removeSkippedTask: (chainId: string, taskId: string): void => { + if (!isBrowser()) return + const skipped = storage.getSkippedTasks(chainId) + const filtered = skipped.filter(id => id !== taskId) + localStorage.setItem(getSkippedTasksKey(chainId), JSON.stringify(filtered)) + }, + + // Проверка, пропущено ли задание + isTaskSkipped: (chainId: string, taskId: string): boolean => { + if (!isBrowser()) return false + const skipped = storage.getSkippedTasks(chainId) + return skipped.includes(taskId) + }, + + // Очистка всех пропущенных заданий цепочки + clearSkippedTasks: (chainId: string): void => { + if (!isBrowser()) return + localStorage.removeItem(getSkippedTasksKey(chainId)) + }, }