import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; import axios from '../../axios'; // Типы данных export interface Submit { id?: number; missionId: number; language: string; languageVersion: string; sourceCode: string; contestId?: number; } export interface Solution { id: number; missionId: number; language: string; languageVersion: string; sourceCode: string; status: string; time: string; testerState: string; testerErrorCode: string; testerMessage: string; currentTest: number; amountOfTests: number; } export interface MissionSubmit { id: number; userId: number; solution: Solution; contestId?: number; contestName?: string; sourceType: string; } interface SubmitState { submits: Submit[]; submitsById: Record; // ✅ добавлено currentSubmit?: Submit; status: 'idle' | 'loading' | 'successful' | 'failed'; error?: string; } // Начальное состояние const initialState: SubmitState = { submits: [], submitsById: {}, // ✅ инициализация currentSubmit: undefined, status: 'idle', error: undefined, }; // AsyncThunk: Отправка решения export const submitMission = createAsyncThunk( 'submit/submitMission', async (submitData: Submit, { rejectWithValue }) => { try { const response = await axios.post('/submits', submitData); return response.data; } catch (err: any) { return rejectWithValue( err.response?.data?.message || 'Submit failed', ); } }, ); // AsyncThunk: Получить все свои отправки export const fetchMySubmits = createAsyncThunk( 'submit/fetchMySubmits', async (_, { rejectWithValue }) => { try { const response = await axios.get('/submits/my'); return response.data as Submit[]; } catch (err: any) { return rejectWithValue( err.response?.data?.message || 'Failed to fetch submits', ); } }, ); // AsyncThunk: Получить конкретную отправку по ID export const fetchSubmitById = createAsyncThunk( 'submit/fetchSubmitById', async (id: number, { rejectWithValue }) => { try { const response = await axios.get(`/submits/${id}`); return response.data as Submit; } catch (err: any) { return rejectWithValue( err.response?.data?.message || 'Failed to fetch submit', ); } }, ); // ✅ AsyncThunk: Получить отправки для конкретной миссии (новая структура) export const fetchMySubmitsByMission = createAsyncThunk( 'submit/fetchMySubmitsByMission', async (missionId: number, { rejectWithValue }) => { try { const response = await axios.get( `/submits/my/mission/${missionId}`, ); return { missionId, data: response.data as MissionSubmit[] }; } catch (err: any) { return rejectWithValue( err.response?.data?.message || 'Failed to fetch mission submits', ); } }, ); // Slice const submitSlice = createSlice({ name: 'submit', initialState, reducers: { clearCurrentSubmit: (state) => { state.currentSubmit = undefined; state.status = 'idle'; state.error = undefined; }, clearSubmitsByMission: (state, action: PayloadAction) => { delete state.submitsById[action.payload]; }, }, extraReducers: (builder) => { // Отправка решения builder.addCase(submitMission.pending, (state) => { state.status = 'loading'; state.error = undefined; }); builder.addCase( submitMission.fulfilled, (state, action: PayloadAction) => { state.status = 'successful'; state.submits.push(action.payload); }, ); builder.addCase( submitMission.rejected, (state, action: PayloadAction) => { state.status = 'failed'; state.error = action.payload; }, ); // Получить все свои отправки builder.addCase(fetchMySubmits.pending, (state) => { state.status = 'loading'; state.error = undefined; }); builder.addCase( fetchMySubmits.fulfilled, (state, action: PayloadAction) => { state.status = 'successful'; state.submits = action.payload; }, ); builder.addCase( fetchMySubmits.rejected, (state, action: PayloadAction) => { state.status = 'failed'; state.error = action.payload; }, ); // Получить отправку по ID builder.addCase(fetchSubmitById.pending, (state) => { state.status = 'loading'; state.error = undefined; }); builder.addCase( fetchSubmitById.fulfilled, (state, action: PayloadAction) => { state.status = 'successful'; state.currentSubmit = action.payload; }, ); builder.addCase( fetchSubmitById.rejected, (state, action: PayloadAction) => { state.status = 'failed'; state.error = action.payload; }, ); // ✅ Получить отправки по миссии builder.addCase(fetchMySubmitsByMission.pending, (state) => { state.status = 'loading'; state.error = undefined; }); builder.addCase( fetchMySubmitsByMission.fulfilled, ( state, action: PayloadAction<{ missionId: number; data: MissionSubmit[]; }>, ) => { state.status = 'successful'; state.submitsById[action.payload.missionId] = action.payload.data; }, ); builder.addCase( fetchMySubmitsByMission.rejected, (state, action: PayloadAction) => { state.status = 'failed'; state.error = action.payload; }, ); }, }); export const { clearCurrentSubmit, clearSubmitsByMission } = submitSlice.actions; export const submitReducer = submitSlice.reducer;