get groups
This commit is contained in:
258
src/redux/slices/groups.ts
Normal file
258
src/redux/slices/groups.ts
Normal file
@@ -0,0 +1,258 @@
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||
import axios from "../../axios";
|
||||
|
||||
// ─── Типы ────────────────────────────────────────────
|
||||
|
||||
export interface GroupMember {
|
||||
userId: number;
|
||||
username: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
members: GroupMember[];
|
||||
contests: any[];
|
||||
}
|
||||
|
||||
interface GroupsState {
|
||||
groups: Group[];
|
||||
currentGroup: Group | null;
|
||||
status: "idle" | "loading" | "successful" | "failed";
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
const initialState: GroupsState = {
|
||||
groups: [],
|
||||
currentGroup: null,
|
||||
status: "idle",
|
||||
error: null,
|
||||
};
|
||||
|
||||
// ─── Async Thunks ─────────────────────────────────────
|
||||
|
||||
// POST /groups
|
||||
export const createGroup = createAsyncThunk(
|
||||
"groups/createGroup",
|
||||
async (
|
||||
{ name, description }: { name: string; description: string },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post("/groups", { name, description });
|
||||
return response.data as Group;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при создании группы");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// PUT /groups/{groupId}
|
||||
export const updateGroup = createAsyncThunk(
|
||||
"groups/updateGroup",
|
||||
async (
|
||||
{ groupId, name, description }: { groupId: number; name: string; description: string },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.put(`/groups/${groupId}`, { name, description });
|
||||
return response.data as Group;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при обновлении группы");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// DELETE /groups/{groupId}
|
||||
export const deleteGroup = createAsyncThunk(
|
||||
"groups/deleteGroup",
|
||||
async (groupId: number, { rejectWithValue }) => {
|
||||
try {
|
||||
await axios.delete(`/groups/${groupId}`);
|
||||
return groupId;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при удалении группы");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// GET /groups/my
|
||||
export const fetchMyGroups = createAsyncThunk(
|
||||
"groups/fetchMyGroups",
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get("/groups/my");
|
||||
return response.data.groups as Group[];
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при получении групп");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// GET /groups/{groupId}
|
||||
export const fetchGroupById = createAsyncThunk(
|
||||
"groups/fetchGroupById",
|
||||
async (groupId: number, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get(`/groups/${groupId}`);
|
||||
return response.data as Group;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при получении группы");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// POST /groups/members
|
||||
export const addGroupMember = createAsyncThunk(
|
||||
"groups/addGroupMember",
|
||||
async ({ userId, role }: { userId: number; role: string }, { rejectWithValue }) => {
|
||||
try {
|
||||
await axios.post("/groups/members", { userId, role });
|
||||
return { userId, role };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при добавлении участника");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// DELETE /groups/{groupId}/members/{memberId}
|
||||
export const removeGroupMember = createAsyncThunk(
|
||||
"groups/removeGroupMember",
|
||||
async (
|
||||
{ groupId, memberId }: { groupId: number; memberId: number },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
try {
|
||||
await axios.delete(`/groups/${groupId}/members/${memberId}`);
|
||||
return { groupId, memberId };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Ошибка при удалении участника");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── Slice ────────────────────────────────────────────
|
||||
|
||||
const groupsSlice = createSlice({
|
||||
name: "groups",
|
||||
initialState,
|
||||
reducers: {
|
||||
clearCurrentGroup: (state) => {
|
||||
state.currentGroup = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
// ─── CREATE GROUP ───
|
||||
builder.addCase(createGroup.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(createGroup.fulfilled, (state, action: PayloadAction<Group>) => {
|
||||
state.status = "successful";
|
||||
state.groups.push(action.payload);
|
||||
});
|
||||
builder.addCase(createGroup.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── UPDATE GROUP ───
|
||||
builder.addCase(updateGroup.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(updateGroup.fulfilled, (state, action: PayloadAction<Group>) => {
|
||||
state.status = "successful";
|
||||
const index = state.groups.findIndex((g) => g.id === action.payload.id);
|
||||
if (index !== -1) state.groups[index] = action.payload;
|
||||
if (state.currentGroup?.id === action.payload.id)
|
||||
state.currentGroup = action.payload;
|
||||
});
|
||||
builder.addCase(updateGroup.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── DELETE GROUP ───
|
||||
builder.addCase(deleteGroup.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(deleteGroup.fulfilled, (state, action: PayloadAction<number>) => {
|
||||
state.status = "successful";
|
||||
state.groups = state.groups.filter((g) => g.id !== action.payload);
|
||||
if (state.currentGroup?.id === action.payload) state.currentGroup = null;
|
||||
});
|
||||
builder.addCase(deleteGroup.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── FETCH MY GROUPS ───
|
||||
builder.addCase(fetchMyGroups.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchMyGroups.fulfilled, (state, action: PayloadAction<Group[]>) => {
|
||||
state.status = "successful";
|
||||
state.groups = action.payload;
|
||||
});
|
||||
builder.addCase(fetchMyGroups.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── FETCH GROUP BY ID ───
|
||||
builder.addCase(fetchGroupById.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchGroupById.fulfilled, (state, action: PayloadAction<Group>) => {
|
||||
state.status = "successful";
|
||||
state.currentGroup = action.payload;
|
||||
});
|
||||
builder.addCase(fetchGroupById.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── ADD MEMBER ───
|
||||
builder.addCase(addGroupMember.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(addGroupMember.fulfilled, (state) => {
|
||||
state.status = "successful";
|
||||
});
|
||||
builder.addCase(addGroupMember.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// ─── REMOVE MEMBER ───
|
||||
builder.addCase(removeGroupMember.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(
|
||||
removeGroupMember.fulfilled,
|
||||
(state, action: PayloadAction<{ groupId: number; memberId: number }>) => {
|
||||
state.status = "successful";
|
||||
if (state.currentGroup && state.currentGroup.id === action.payload.groupId) {
|
||||
state.currentGroup.members = state.currentGroup.members.filter(
|
||||
(m) => m.userId !== action.payload.memberId
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
builder.addCase(removeGroupMember.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { clearCurrentGroup } = groupsSlice.actions;
|
||||
export const groupsReducer = groupsSlice.reducer;
|
||||
@@ -4,6 +4,7 @@ import { storeReducer } from "./slices/store";
|
||||
import { missionsReducer } from "./slices/missions";
|
||||
import { submitReducer } from "./slices/submit";
|
||||
import { contestsReducer } from "./slices/contests";
|
||||
import { groupsReducer } from "./slices/groups";
|
||||
|
||||
|
||||
// использование
|
||||
@@ -23,6 +24,7 @@ export const store = configureStore({
|
||||
missions: missionsReducer,
|
||||
submin: submitReducer,
|
||||
contests: contestsReducer,
|
||||
groups: groupsReducer,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user