122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
import BASE_URL from "../config";
|
|
import { getNonNullValues } from "../../common/utils";
|
|
import { Channel, UpdateChannelDTO, UpdatePinnedMessageDTO } from "../../types/channel";
|
|
|
|
interface StoredChannel extends Channel {
|
|
icon: string;
|
|
}
|
|
|
|
interface State {
|
|
ids: number[];
|
|
byId: { [id: number]: StoredChannel | undefined };
|
|
}
|
|
|
|
const initialState: State = {
|
|
ids: [],
|
|
byId: {}
|
|
};
|
|
|
|
const channelsSlice = createSlice({
|
|
name: `channels`,
|
|
initialState,
|
|
reducers: {
|
|
resetChannels() {
|
|
return initialState;
|
|
},
|
|
fullfillChannels(state, action: PayloadAction<Channel[]>) {
|
|
const channels = action.payload || [];
|
|
state.ids = channels.map(({ gid }) => gid);
|
|
channels.forEach((c) => {
|
|
state.byId[c.gid] = {
|
|
...c,
|
|
icon:
|
|
c.avatar_updated_at == 0
|
|
? ""
|
|
: `${BASE_URL}/resource/group_avatar?gid=${c.gid}&t=${c.avatar_updated_at}`
|
|
};
|
|
});
|
|
},
|
|
addChannel(state, action: PayloadAction<Channel>) {
|
|
const ch = action.payload;
|
|
const { gid, avatar_updated_at } = ch;
|
|
if (!state.ids.includes(+gid)) {
|
|
state.ids.push(+gid);
|
|
}
|
|
state.byId[gid] = {
|
|
...ch,
|
|
icon:
|
|
avatar_updated_at == 0
|
|
? ""
|
|
: `${BASE_URL}/resource/group_avatar?gid=${gid}&t=${avatar_updated_at}`
|
|
};
|
|
},
|
|
updateChannel(state, action: PayloadAction<UpdateChannelDTO>) {
|
|
const ignoreInPublic = ["add_member", "remove_member"];
|
|
const { gid, operation, members = [], ...rest } = action.payload;
|
|
const currChannel = state.byId[gid];
|
|
if (!currChannel || (currChannel.is_public && ignoreInPublic.includes(operation))) return;
|
|
switch (operation) {
|
|
case "remove_member": {
|
|
state.byId[gid]!.members = state.byId[gid]!.members.filter(
|
|
(id) => members.findIndex((uid) => uid == id) == -1
|
|
);
|
|
break;
|
|
}
|
|
case "add_member": {
|
|
const currs = state.byId[gid]!.members;
|
|
const _set = new Set([...currs, ...members]);
|
|
state.byId[gid]!.members = Array.from(_set);
|
|
break;
|
|
}
|
|
default:
|
|
state.byId[gid] = { ...state.byId[gid]!, ...getNonNullValues(rest) };
|
|
break;
|
|
}
|
|
},
|
|
updatePinMessage(state, action: PayloadAction<UpdatePinnedMessageDTO>) {
|
|
const { gid, mid, msg } = action.payload;
|
|
let pinnedMessages = state.byId[gid]?.pinned_messages;
|
|
// add
|
|
if (msg) {
|
|
if (!pinnedMessages) {
|
|
pinnedMessages = [msg];
|
|
} else {
|
|
const idx = pinnedMessages.findIndex((msg) => msg.mid == mid);
|
|
if (idx > -1) {
|
|
pinnedMessages.splice(idx, 1);
|
|
}
|
|
pinnedMessages.push(msg);
|
|
}
|
|
} else {
|
|
// remove
|
|
if (pinnedMessages) {
|
|
const idx = pinnedMessages.findIndex((m) => m.mid == mid);
|
|
if (idx > -1) {
|
|
pinnedMessages.splice(idx, 1);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
removeChannel(state, action: PayloadAction<number>) {
|
|
const gid = action.payload;
|
|
const idx = state.ids.findIndex((i) => i == gid);
|
|
if (idx > -1) {
|
|
state.ids.splice(idx, 1);
|
|
delete state.byId[gid];
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
export const {
|
|
updatePinMessage,
|
|
resetChannels,
|
|
fullfillChannels,
|
|
addChannel,
|
|
updateChannel,
|
|
removeChannel
|
|
} = channelsSlice.actions;
|
|
|
|
export default channelsSlice.reducer;
|