Files
LiquidCode_Frontend/src/redux/slices/submit.ts
Виталий Лавшонок 56b6f9b339 group posts
2025-11-15 22:23:26 +03:00

225 lines
6.7 KiB
TypeScript

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<number, MissionSubmit[]>; // ✅ добавлено
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<number>) => {
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<Submit>) => {
state.status = 'successful';
state.submits.push(action.payload);
},
);
builder.addCase(
submitMission.rejected,
(state, action: PayloadAction<any>) => {
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<Submit[]>) => {
state.status = 'successful';
state.submits = action.payload;
},
);
builder.addCase(
fetchMySubmits.rejected,
(state, action: PayloadAction<any>) => {
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<Submit>) => {
state.status = 'successful';
state.currentSubmit = action.payload;
},
);
builder.addCase(
fetchSubmitById.rejected,
(state, action: PayloadAction<any>) => {
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<any>) => {
state.status = 'failed';
state.error = action.payload;
},
);
},
});
export const { clearCurrentSubmit, clearSubmitsByMission } =
submitSlice.actions;
export const submitReducer = submitSlice.reducer;