dont work

This commit is contained in:
Виталий Лавшонок
2025-11-06 15:09:10 +03:00
parent dc6df1480e
commit 1b39b8c77f
6 changed files with 546 additions and 42 deletions

View File

@@ -15,7 +15,7 @@ export interface Mission {
updatedAt: string;
timeLimitMilliseconds: number;
memoryLimitBytes: number;
statements: null;
statements: string;
}
export interface Member {
@@ -24,18 +24,22 @@ export interface Member {
role: string;
}
export interface Group {
groupId: number;
groupName: string;
}
export interface Contest {
id: number;
name: string;
description: string;
scheduleType: string;
scheduleType: 'AlwaysOpen' | 'FixedWindow' | 'RollingWindow';
startsAt: string;
endsAt: string;
attemptDurationMinutes: number | null;
maxAttempts: number | null;
allowEarlyFinish: boolean | null;
groupId: number | null;
groupName: string | null;
attemptDurationMinutes: number;
maxAttempts: number;
allowEarlyFinish: boolean;
groups: Group[];
missions: Mission[];
articles: any[];
members: Member[];
@@ -47,20 +51,18 @@ interface ContestsResponse {
}
export interface CreateContestBody {
name?: string | null;
description?: string | null;
name: string;
description: string;
scheduleType: 'AlwaysOpen' | 'FixedWindow' | 'RollingWindow';
visibility: 'Public' | 'GroupPrivate';
startsAt?: string | null;
endsAt?: string | null;
attemptDurationMinutes?: number | null;
maxAttempts?: number | null;
allowEarlyFinish?: boolean | null;
groupId?: number | null;
missionIds?: number[] | null;
articleIds?: number[] | null;
participantIds?: number[] | null;
organizerIds?: number[] | null;
startsAt: string;
endsAt: string;
attemptDurationMinutes: number;
maxAttempts: number;
allowEarlyFinish: boolean;
groupId: number;
missionIds: number[];
articleIds: number[];
}
// =====================
@@ -77,12 +79,22 @@ interface ContestsState {
error: string | null;
};
fetchContestById: {
contest: Contest | null;
contest: Contest;
status: Status;
error: string | null;
};
createContest: {
contest: Contest | null;
contest: Contest;
status: Status;
error: string | null;
};
// 🆕 Добавляем updateContest и deleteContest
updateContest: {
contest: Contest;
status: Status;
error: string | null;
};
deleteContest: {
status: Status;
error: string | null;
};
@@ -107,12 +119,63 @@ const initialState: ContestsState = {
error: null,
},
fetchContestById: {
contest: null,
contest: {
id: 0,
name: '',
description: '',
scheduleType: 'AlwaysOpen',
startsAt: '',
endsAt: '',
attemptDurationMinutes: 0,
maxAttempts: 0,
allowEarlyFinish: false,
groups: [],
missions: [],
articles: [],
members: [],
},
status: 'idle',
error: null,
},
createContest: {
contest: null,
contest: {
id: 0,
name: '',
description: '',
scheduleType: 'AlwaysOpen',
startsAt: '',
endsAt: '',
attemptDurationMinutes: 0,
maxAttempts: 0,
allowEarlyFinish: false,
groups: [],
missions: [],
articles: [],
members: [],
},
status: 'idle',
error: null,
},
updateContest: {
contest: {
id: 0,
name: '',
description: '',
scheduleType: 'AlwaysOpen',
startsAt: '',
endsAt: '',
attemptDurationMinutes: 0,
maxAttempts: 0,
allowEarlyFinish: false,
groups: [],
missions: [],
articles: [],
members: [],
},
status: 'idle',
error: null,
},
deleteContest: {
status: 'idle',
error: null,
},
@@ -191,13 +254,51 @@ export const createContest = createAsyncThunk(
},
);
// 🆕 Обновление контеста
export const updateContest = createAsyncThunk(
'contests/update',
async (
{
contestId,
...contestData
}: { contestId: number } & CreateContestBody,
{ rejectWithValue },
) => {
try {
const response = await axios.patch<Contest>(
`/contests/${contestId}`,
contestData,
);
return response.data;
} catch (err: any) {
return rejectWithValue(
err.response?.data?.message || 'Failed to update contest',
);
}
},
);
// 🆕 Удаление контеста
export const deleteContest = createAsyncThunk(
'contests/delete',
async (contestId: number, { rejectWithValue }) => {
try {
await axios.delete(`/contests/${contestId}`);
return contestId;
} catch (err: any) {
return rejectWithValue(
err.response?.data?.message || 'Failed to delete contest',
);
}
},
);
// Контесты, созданные мной
export const fetchMyContests = createAsyncThunk(
'contests/fetchMyContests',
async (_, { rejectWithValue }) => {
try {
const response = await axios.get<Contest[]>('/contests/my');
// Возвращаем просто массив контестов
return response.data;
} catch (err: any) {
return rejectWithValue(
@@ -238,8 +339,15 @@ const contestsSlice = createSlice({
name: 'contests',
initialState,
reducers: {
clearSelectedContest: (state) => {
state.fetchContestById.contest = null;
// 🆕 Сброс статусов
setContestStatus: (
state,
action: PayloadAction<{ key: keyof ContestsState; status: Status }>,
) => {
const { key, status } = action.payload;
if (state[key]) {
(state[key] as any).status = status;
}
},
},
extraReducers: (builder) => {
@@ -295,7 +403,48 @@ const contestsSlice = createSlice({
state.createContest.error = action.payload;
});
// fetchMyContests
// 🆕 updateContest
builder.addCase(updateContest.pending, (state) => {
state.updateContest.status = 'loading';
state.updateContest.error = null;
});
builder.addCase(
updateContest.fulfilled,
(state, action: PayloadAction<Contest>) => {
state.updateContest.status = 'successful';
state.updateContest.contest = action.payload;
},
);
builder.addCase(updateContest.rejected, (state, action: any) => {
state.updateContest.status = 'failed';
state.updateContest.error = action.payload;
});
// 🆕 deleteContest
builder.addCase(deleteContest.pending, (state) => {
state.deleteContest.status = 'loading';
state.deleteContest.error = null;
});
builder.addCase(
deleteContest.fulfilled,
(state, action: PayloadAction<number>) => {
state.deleteContest.status = 'successful';
// Удалим контест из списков
state.fetchContests.contests =
state.fetchContests.contests.filter(
(c) => c.id !== action.payload,
);
state.fetchMyContests.contests =
state.fetchMyContests.contests.filter(
(c) => c.id !== action.payload,
);
},
);
builder.addCase(deleteContest.rejected, (state, action: any) => {
state.deleteContest.status = 'failed';
state.deleteContest.error = action.payload;
});
// fetchMyContests
builder.addCase(fetchMyContests.pending, (state) => {
state.fetchMyContests.status = 'loading';
@@ -342,5 +491,5 @@ const contestsSlice = createSlice({
// Экспорты
// =====================
export const { clearSelectedContest } = contestsSlice.actions;
export const { setContestStatus } = contestsSlice.actions;
export const contestsReducer = contestsSlice.reducer;