Files
ColdBreeze-chat-web/src/app/slices/channels.ts
T

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;