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) { 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) { 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) { 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) { 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) { 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;