submissions
This commit is contained in:
@@ -77,6 +77,22 @@ export const fetchWhoAmI = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
// AsyncThunk: Загрузка токенов из localStorage
|
||||
export const loadTokensFromLocalStorage = createAsyncThunk(
|
||||
"auth/loadTokens",
|
||||
async (_, { dispatch }) => {
|
||||
const jwt = localStorage.getItem("jwt");
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
|
||||
if (jwt && refreshToken) {
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${jwt}`;
|
||||
return { jwt, refreshToken };
|
||||
} else {
|
||||
return { jwt: null, refreshToken: null };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Slice
|
||||
const authSlice = createSlice({
|
||||
name: "auth",
|
||||
@@ -88,6 +104,9 @@ const authSlice = createSlice({
|
||||
state.username = null;
|
||||
state.status = "idle";
|
||||
state.error = null;
|
||||
localStorage.removeItem("jwt");
|
||||
localStorage.removeItem("refreshToken");
|
||||
delete axios.defaults.headers.common['Authorization'];
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
@@ -98,9 +117,11 @@ const authSlice = createSlice({
|
||||
});
|
||||
builder.addCase(registerUser.fulfilled, (state, action: PayloadAction<{ jwt: string; refreshToken: string }>) => {
|
||||
state.status = "successful";
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${action.payload.jwt}`;
|
||||
state.jwt = action.payload.jwt;
|
||||
state.refreshToken = action.payload.refreshToken;
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${action.payload.jwt}`;
|
||||
localStorage.setItem("jwt", action.payload.jwt);
|
||||
localStorage.setItem("refreshToken", action.payload.refreshToken);
|
||||
});
|
||||
builder.addCase(registerUser.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
@@ -114,9 +135,11 @@ const authSlice = createSlice({
|
||||
});
|
||||
builder.addCase(loginUser.fulfilled, (state, action: PayloadAction<{ jwt: string; refreshToken: string }>) => {
|
||||
state.status = "successful";
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${action.payload.jwt}`;
|
||||
state.jwt = action.payload.jwt;
|
||||
state.refreshToken = action.payload.refreshToken;
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${action.payload.jwt}`;
|
||||
localStorage.setItem("jwt", action.payload.jwt);
|
||||
localStorage.setItem("refreshToken", action.payload.refreshToken);
|
||||
});
|
||||
builder.addCase(loginUser.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
@@ -150,6 +173,15 @@ const authSlice = createSlice({
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// Загрузка токенов из localStorage
|
||||
builder.addCase(loadTokensFromLocalStorage.fulfilled, (state, action: PayloadAction<{ jwt: string | null; refreshToken: string | null }>) => {
|
||||
state.jwt = action.payload.jwt;
|
||||
state.refreshToken = action.payload.refreshToken;
|
||||
if (action.payload.jwt) {
|
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${action.payload.jwt}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ interface Mission {
|
||||
tags: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
statements: Statement[] | null;
|
||||
statements?: Statement[];
|
||||
}
|
||||
|
||||
interface MissionsState {
|
||||
@@ -120,7 +120,6 @@ const missionsSlice = createSlice({
|
||||
});
|
||||
builder.addCase(fetchMissionById.fulfilled, (state, action: PayloadAction<Mission>) => {
|
||||
state.status = "successful";
|
||||
console.log(action.payload);
|
||||
state.currentMission = action.payload;
|
||||
});
|
||||
builder.addCase(fetchMissionById.rejected, (state, action: PayloadAction<any>) => {
|
||||
|
||||
@@ -11,17 +11,33 @@ export interface Submit {
|
||||
contestId: number | null;
|
||||
}
|
||||
|
||||
export interface SubmitStatus {
|
||||
SubmitId: number;
|
||||
State: string;
|
||||
ErrorCode: string;
|
||||
Message: string;
|
||||
CurrentTest: number;
|
||||
AmountOfTests: 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 | null;
|
||||
contestName: string | null;
|
||||
sourceType: string;
|
||||
}
|
||||
|
||||
interface SubmitState {
|
||||
submits: Submit[];
|
||||
submitsById: Record<number, MissionSubmit[]>; // ✅ добавлено
|
||||
currentSubmit?: Submit;
|
||||
status: "idle" | "loading" | "successful" | "failed";
|
||||
error: string | null;
|
||||
@@ -30,6 +46,7 @@ interface SubmitState {
|
||||
// Начальное состояние
|
||||
const initialState: SubmitState = {
|
||||
submits: [],
|
||||
submitsById: {}, // ✅ инициализация
|
||||
currentSubmit: undefined,
|
||||
status: "idle",
|
||||
error: null,
|
||||
@@ -74,13 +91,13 @@ export const fetchSubmitById = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
// AsyncThunk: Получить свои отправки для конкретной миссии
|
||||
// ✅ AsyncThunk: Получить отправки для конкретной миссии (новая структура)
|
||||
export const fetchMySubmitsByMission = createAsyncThunk(
|
||||
"submit/fetchMySubmitsByMission",
|
||||
async (missionId: number, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get(`/submits/my/mission/${missionId}`);
|
||||
return response.data as Submit[];
|
||||
return { missionId, data: response.data as MissionSubmit[] };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Failed to fetch mission submits");
|
||||
}
|
||||
@@ -97,6 +114,9 @@ const submitSlice = createSlice({
|
||||
state.status = "idle";
|
||||
state.error = null;
|
||||
},
|
||||
clearSubmitsByMission: (state, action: PayloadAction<number>) => {
|
||||
delete state.submitsById[action.payload];
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
// Отправка решения
|
||||
@@ -141,15 +161,18 @@ const submitSlice = createSlice({
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// Получить отправки по миссии
|
||||
// ✅ Получить отправки по миссии
|
||||
builder.addCase(fetchMySubmitsByMission.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchMySubmitsByMission.fulfilled, (state, action: PayloadAction<Submit[]>) => {
|
||||
state.status = "successful";
|
||||
state.submits = action.payload;
|
||||
});
|
||||
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;
|
||||
@@ -157,5 +180,5 @@ const submitSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { clearCurrentSubmit } = submitSlice.actions;
|
||||
export const { clearCurrentSubmit, clearSubmitsByMission } = submitSlice.actions;
|
||||
export const submitReducer = submitSlice.reducer;
|
||||
|
||||
Reference in New Issue
Block a user