diff --git a/src/app/listener.middleware/handler.channels.ts b/src/app/listener.middleware/handler.channels.ts index 6a0e3549..417e03a6 100644 --- a/src/app/listener.middleware/handler.channels.ts +++ b/src/app/listener.middleware/handler.channels.ts @@ -17,7 +17,7 @@ export default async function handler({ operation, data, payload }: Params) { { const chs = payload as Channel[]; const arr = chs.map(({ gid, ...rest }) => { - return { key: gid + "", value: rest }; + return { key: gid + "", value: { gid, ...rest } }; }); await table.setItems(arr); } @@ -40,6 +40,7 @@ export default async function handler({ operation, data, payload }: Params) { await table?.setItem(id + "", data.byId[id]); } break; + default: break; } diff --git a/src/app/listener.middleware/handler.footprint.ts b/src/app/listener.middleware/handler.footprint.ts index eee36cd9..4b1572ce 100644 --- a/src/app/listener.middleware/handler.footprint.ts +++ b/src/app/listener.middleware/handler.footprint.ts @@ -69,6 +69,11 @@ export default async function handler({ operation, data = {}, payload }: Params) await table?.setItem("autoDeleteMsgChannels", data.autoDeleteMsgChannels || []); } break; + case "updateChannelVisibleAside": + { + await table?.setItem("channelAsides", data.channelAsides); + } + break; default: break; } diff --git a/src/app/slices/channels.ts b/src/app/slices/channels.ts index aac1eaef..ac6354c3 100644 --- a/src/app/slices/channels.ts +++ b/src/app/slices/channels.ts @@ -2,13 +2,10 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { isNull, omitBy } from "lodash"; import BASE_URL from "../config"; import { Channel, UpdateChannelDTO, UpdatePinnedMessageDTO } from "../../types/channel"; -import { resetAuthData } from "./auth.data"; // import { updateVoicingInfo } from "./voice"; -type ChannelAside = "members" | "voice" | null; interface StoredChannel extends Channel { icon?: string; - visibleAside: ChannelAside } interface State { @@ -28,9 +25,10 @@ const channelsSlice = createSlice({ resetChannels() { return initialState; }, - fillChannels(state, action: PayloadAction) { + fillChannels(state, action: PayloadAction) { const channels = action.payload || []; state.ids = channels.map(({ gid }) => gid); + channels.forEach((c) => { state.byId[c.gid] = { ...c, @@ -38,7 +36,6 @@ const channelsSlice = createSlice({ c.avatar_updated_at == 0 ? "" : `${BASE_URL}/resource/group_avatar?gid=${c.gid}&t=${c.avatar_updated_at}`, - visibleAside: state.byId[c.gid]?.visibleAside ?? null }; }); }, @@ -54,7 +51,6 @@ const channelsSlice = createSlice({ avatar_updated_at == 0 ? "" : `${BASE_URL}/resource/group_avatar?gid=${gid}&t=${avatar_updated_at}`, - visibleAside: "members" }; }, updateChannel(state, action: PayloadAction) { @@ -105,12 +101,6 @@ const channelsSlice = createSlice({ } } }, - updateChannelVisibleAside(state, action: PayloadAction<{ id: number, aside: ChannelAside }>) { - const { id, aside } = action.payload; - if (state.byId[id]) { - state.byId[id].visibleAside = aside; - } - }, removeChannel(state, action: PayloadAction) { const gid = action.payload; const idx = state.ids.findIndex((i) => i == gid); @@ -120,16 +110,7 @@ const channelsSlice = createSlice({ } } }, - extraReducers: (builder) => { - builder.addCase(resetAuthData, (state) => { - // 如果有aside是voice的,就把它关掉 - Object.values(state.byId).forEach((ch) => { - if (ch.visibleAside === "voice") { - ch.visibleAside = null; - } - }); - }); - } + }); export const { @@ -139,7 +120,6 @@ export const { addChannel, updateChannel, removeChannel, - updateChannelVisibleAside } = channelsSlice.actions; export default channelsSlice.reducer; diff --git a/src/app/slices/footprint.ts b/src/app/slices/footprint.ts index 27927939..0479fc37 100644 --- a/src/app/slices/footprint.ts +++ b/src/app/slices/footprint.ts @@ -2,7 +2,9 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { MuteDTO } from "../../types/message"; import { OG } from "../../types/resource"; import { AutoDeleteMessageSettingDTO, AutoDeleteMsgForGroup, AutoDeleteMsgForUser, AutoDeleteSettingForChannels, AutoDeleteSettingForUsers } from "../../types/sse"; +import { resetAuthData } from "./auth.data"; +type ChannelAside = "members" | "voice" | null; export interface State { og: { [url: string]: OG } usersVersion: number; @@ -15,8 +17,10 @@ export interface State { muteChannels: { [cid: number]: { expired_in?: number } | undefined }; autoDeleteMsgUsers: AutoDeleteMsgForUser[]; autoDeleteMsgChannels: AutoDeleteMsgForGroup[]; + channelAsides: { [cid: number]: ChannelAside }; } + const initialState: State = { og: {}, usersVersion: 0, @@ -29,6 +33,7 @@ const initialState: State = { muteChannels: {}, autoDeleteMsgUsers: [], autoDeleteMsgChannels: [], + channelAsides: {} }; const footprintSlice = createSlice({ @@ -50,7 +55,8 @@ const footprintSlice = createSlice({ muteUsers = {}, muteChannels = {}, autoDeleteMsgUsers = [], - autoDeleteMsgChannels = [] + autoDeleteMsgChannels = [], + channelAsides = {} } = action.payload; return { og, @@ -63,7 +69,8 @@ const footprintSlice = createSlice({ muteUsers, muteChannels, autoDeleteMsgUsers, - autoDeleteMsgChannels + autoDeleteMsgChannels, + channelAsides }; }, updateUsersVersion(state, action: PayloadAction) { @@ -177,7 +184,21 @@ const footprintSlice = createSlice({ reads.forEach(({ gid, mid }) => { state.readChannels[gid] = mid; }); - } + }, + updateChannelVisibleAside(state, action: PayloadAction<{ id: number, aside: ChannelAside }>) { + const { id, aside } = action.payload; + state.channelAsides[id] = aside; + }, + }, + extraReducers: (builder) => { + builder.addCase(resetAuthData, (state) => { + // 如果有aside是voice的,就把它关掉 + Object.keys(state.channelAsides).forEach((channel_id: string) => { + if (state.channelAsides[+channel_id] === "voice") { + state.channelAsides[+channel_id] = null; + } + }); + }); } }); @@ -191,7 +212,8 @@ export const { updateMute, updateAutoDeleteSetting, updateHistoryMark, - upsertOG + upsertOG, + updateChannelVisibleAside } = footprintSlice.actions; export default footprintSlice.reducer; diff --git a/src/common/component/Voice.tsx b/src/common/component/Voice.tsx index 8b2324ee..91de2221 100644 --- a/src/common/component/Voice.tsx +++ b/src/common/component/Voice.tsx @@ -2,7 +2,7 @@ import AgoraRTC, { IMicrophoneAudioTrack } from 'agora-rtc-sdk-ng'; import { memo, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { useGetAgoraConfigQuery, useGetAgoraVoicingListQuery, useLazyGetAgoraTokenQuery } from '../../app/services/server'; -import { updateChannelVisibleAside } from '../../app/slices/channels'; +import { updateChannelVisibleAside } from '../../app/slices/footprint'; import { addVoiceMember, removeVoiceMember, updateConnectionState, updateDeafenStatus, updateMuteStatus, updateVoicingInfo, updateVoicingMember, updateVoicingNetworkQuality, upsertVoiceList } from '../../app/slices/voice'; import { useAppSelector } from '../../app/store'; import AudioJoin from '../../assets/join.wav'; diff --git a/src/routes/chat/ChannelChat/index.tsx b/src/routes/chat/ChannelChat/index.tsx index 0982bfb1..960d9885 100644 --- a/src/routes/chat/ChannelChat/index.tsx +++ b/src/routes/chat/ChannelChat/index.tsx @@ -17,7 +17,7 @@ import { useAppSelector } from "../../../app/store"; import GoBackNav from "../../../common/component/GoBackNav"; import Members from "./Members"; import VoiceChat from "../VoiceChat"; -import { updateChannelVisibleAside } from "../../../app/slices/channels"; +import { updateChannelVisibleAside } from "../../../app/slices/footprint"; import Dashboard from "../VoiceChat/Dashboard"; type Props = { cid?: number; @@ -33,11 +33,13 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) { userIds, data, loginUser, + visibleAside } = useAppSelector((store) => { return { loginUser: store.authData.user, userIds: store.users.ids, data: store.channels.byId[cid], + visibleAside: store.footprint.channelAsides[cid] }; }); useEffect(() => { @@ -56,7 +58,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) { const toggleMembersVisible = () => { dispatch(updateChannelVisibleAside({ id: cid, - aside: data.visibleAside !== "members" ? "members" : null + aside: visibleAside !== "members" ? "members" : null })); }; @@ -109,7 +111,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) { onClick={toggleMembersVisible} > - + @@ -125,10 +127,10 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) { } users={ - + } voice={ - + } />; } diff --git a/src/routes/chat/VoiceChat/index.tsx b/src/routes/chat/VoiceChat/index.tsx index a658b5c7..8632cc38 100644 --- a/src/routes/chat/VoiceChat/index.tsx +++ b/src/routes/chat/VoiceChat/index.tsx @@ -3,7 +3,7 @@ // import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; -import { updateChannelVisibleAside } from '../../../app/slices/channels'; +import { updateChannelVisibleAside } from '../../../app/slices/footprint'; import { useAppSelector } from '../../../app/store'; import IconHeadphone from '../../../assets/icons/headphone.svg'; import Tooltip from '../../../common/component/Tooltip'; @@ -18,11 +18,12 @@ type Props = { const VoiceChat = ({ id, context = "channel" }: Props) => { const { joinVoice, joined, joining = false, joinedAtThisContext } = useVoice({ id, context }); const dispatch = useDispatch(); - const { loginUser, contextData, voiceList } = useAppSelector(store => { + const { loginUser, voiceList, visibleAside } = useAppSelector(store => { return { loginUser: store.authData.user, contextData: context == "channel" ? store.channels.byId[id] : store.users.byId[id], - voiceList: store.voice.list + voiceList: store.voice.list, + visibleAside: context == "channel" ? store.footprint.channelAsides[id] : null, }; }); const { data: agoraConfig } = useGetAgoraConfigQuery(undefined, { skip: !loginUser?.is_admin }); @@ -31,7 +32,7 @@ const VoiceChat = ({ id, context = "channel" }: Props) => { if (context == "channel") { dispatch(updateChannelVisibleAside({ id, - aside: contextData.visibleAside == "voice" ? null : "voice" + aside: visibleAside == "voice" ? null : "voice" })); } // todo DM @@ -51,7 +52,7 @@ const VoiceChat = ({ id, context = "channel" }: Props) => { }; // 只有admin才能看到入口,后续会改 if (!loginUser || !loginUser.is_admin || !agoraConfig?.enabled) return null; - const visible = contextData.visibleAside == "voice"; + const visible = visibleAside == "voice"; const memberCount = voiceList.find((v) => v.context == context && v.id == id)?.memberCount ?? 0; const badgeClass = `absolute -top-2 -right-2 w-4 h-4 rounded-full bg-primary-400 text-white `; return (