refactor: remember channel aside

This commit is contained in:
Tristan Yang
2023-04-18 21:55:56 +08:00
parent 0e77e90664
commit 03d4803034
7 changed files with 50 additions and 39 deletions
@@ -17,7 +17,7 @@ export default async function handler({ operation, data, payload }: Params) {
{ {
const chs = payload as Channel[]; const chs = payload as Channel[];
const arr = chs.map(({ gid, ...rest }) => { const arr = chs.map(({ gid, ...rest }) => {
return { key: gid + "", value: rest }; return { key: gid + "", value: { gid, ...rest } };
}); });
await table.setItems(arr); await table.setItems(arr);
} }
@@ -40,6 +40,7 @@ export default async function handler({ operation, data, payload }: Params) {
await table?.setItem(id + "", data.byId[id]); await table?.setItem(id + "", data.byId[id]);
} }
break; break;
default: default:
break; break;
} }
@@ -69,6 +69,11 @@ export default async function handler({ operation, data = {}, payload }: Params)
await table?.setItem("autoDeleteMsgChannels", data.autoDeleteMsgChannels || []); await table?.setItem("autoDeleteMsgChannels", data.autoDeleteMsgChannels || []);
} }
break; break;
case "updateChannelVisibleAside":
{
await table?.setItem("channelAsides", data.channelAsides);
}
break;
default: default:
break; break;
} }
+3 -23
View File
@@ -2,13 +2,10 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { isNull, omitBy } from "lodash"; import { isNull, omitBy } from "lodash";
import BASE_URL from "../config"; import BASE_URL from "../config";
import { Channel, UpdateChannelDTO, UpdatePinnedMessageDTO } from "../../types/channel"; import { Channel, UpdateChannelDTO, UpdatePinnedMessageDTO } from "../../types/channel";
import { resetAuthData } from "./auth.data";
// import { updateVoicingInfo } from "./voice"; // import { updateVoicingInfo } from "./voice";
type ChannelAside = "members" | "voice" | null;
interface StoredChannel extends Channel { interface StoredChannel extends Channel {
icon?: string; icon?: string;
visibleAside: ChannelAside
} }
interface State { interface State {
@@ -28,9 +25,10 @@ const channelsSlice = createSlice({
resetChannels() { resetChannels() {
return initialState; return initialState;
}, },
fillChannels(state, action: PayloadAction<Channel[]>) { fillChannels(state, action: PayloadAction<StoredChannel[]>) {
const channels = action.payload || []; const channels = action.payload || [];
state.ids = channels.map(({ gid }) => gid); state.ids = channels.map(({ gid }) => gid);
channels.forEach((c) => { channels.forEach((c) => {
state.byId[c.gid] = { state.byId[c.gid] = {
...c, ...c,
@@ -38,7 +36,6 @@ const channelsSlice = createSlice({
c.avatar_updated_at == 0 c.avatar_updated_at == 0
? "" ? ""
: `${BASE_URL}/resource/group_avatar?gid=${c.gid}&t=${c.avatar_updated_at}`, : `${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 avatar_updated_at == 0
? "" ? ""
: `${BASE_URL}/resource/group_avatar?gid=${gid}&t=${avatar_updated_at}`, : `${BASE_URL}/resource/group_avatar?gid=${gid}&t=${avatar_updated_at}`,
visibleAside: "members"
}; };
}, },
updateChannel(state, action: PayloadAction<UpdateChannelDTO>) { updateChannel(state, action: PayloadAction<UpdateChannelDTO>) {
@@ -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<number>) { removeChannel(state, action: PayloadAction<number>) {
const gid = action.payload; const gid = action.payload;
const idx = state.ids.findIndex((i) => i == gid); 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 { export const {
@@ -139,7 +120,6 @@ export const {
addChannel, addChannel,
updateChannel, updateChannel,
removeChannel, removeChannel,
updateChannelVisibleAside
} = channelsSlice.actions; } = channelsSlice.actions;
export default channelsSlice.reducer; export default channelsSlice.reducer;
+26 -4
View File
@@ -2,7 +2,9 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { MuteDTO } from "../../types/message"; import { MuteDTO } from "../../types/message";
import { OG } from "../../types/resource"; import { OG } from "../../types/resource";
import { AutoDeleteMessageSettingDTO, AutoDeleteMsgForGroup, AutoDeleteMsgForUser, AutoDeleteSettingForChannels, AutoDeleteSettingForUsers } from "../../types/sse"; import { AutoDeleteMessageSettingDTO, AutoDeleteMsgForGroup, AutoDeleteMsgForUser, AutoDeleteSettingForChannels, AutoDeleteSettingForUsers } from "../../types/sse";
import { resetAuthData } from "./auth.data";
type ChannelAside = "members" | "voice" | null;
export interface State { export interface State {
og: { [url: string]: OG } og: { [url: string]: OG }
usersVersion: number; usersVersion: number;
@@ -15,8 +17,10 @@ export interface State {
muteChannels: { [cid: number]: { expired_in?: number } | undefined }; muteChannels: { [cid: number]: { expired_in?: number } | undefined };
autoDeleteMsgUsers: AutoDeleteMsgForUser[]; autoDeleteMsgUsers: AutoDeleteMsgForUser[];
autoDeleteMsgChannels: AutoDeleteMsgForGroup[]; autoDeleteMsgChannels: AutoDeleteMsgForGroup[];
channelAsides: { [cid: number]: ChannelAside };
} }
const initialState: State = { const initialState: State = {
og: {}, og: {},
usersVersion: 0, usersVersion: 0,
@@ -29,6 +33,7 @@ const initialState: State = {
muteChannels: {}, muteChannels: {},
autoDeleteMsgUsers: [], autoDeleteMsgUsers: [],
autoDeleteMsgChannels: [], autoDeleteMsgChannels: [],
channelAsides: {}
}; };
const footprintSlice = createSlice({ const footprintSlice = createSlice({
@@ -50,7 +55,8 @@ const footprintSlice = createSlice({
muteUsers = {}, muteUsers = {},
muteChannels = {}, muteChannels = {},
autoDeleteMsgUsers = [], autoDeleteMsgUsers = [],
autoDeleteMsgChannels = [] autoDeleteMsgChannels = [],
channelAsides = {}
} = action.payload; } = action.payload;
return { return {
og, og,
@@ -63,7 +69,8 @@ const footprintSlice = createSlice({
muteUsers, muteUsers,
muteChannels, muteChannels,
autoDeleteMsgUsers, autoDeleteMsgUsers,
autoDeleteMsgChannels autoDeleteMsgChannels,
channelAsides
}; };
}, },
updateUsersVersion(state, action: PayloadAction<number>) { updateUsersVersion(state, action: PayloadAction<number>) {
@@ -177,7 +184,21 @@ const footprintSlice = createSlice({
reads.forEach(({ gid, mid }) => { reads.forEach(({ gid, mid }) => {
state.readChannels[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, updateMute,
updateAutoDeleteSetting, updateAutoDeleteSetting,
updateHistoryMark, updateHistoryMark,
upsertOG upsertOG,
updateChannelVisibleAside
} = footprintSlice.actions; } = footprintSlice.actions;
export default footprintSlice.reducer; export default footprintSlice.reducer;
+1 -1
View File
@@ -2,7 +2,7 @@ import AgoraRTC, { IMicrophoneAudioTrack } from 'agora-rtc-sdk-ng';
import { memo, useEffect } from 'react'; import { memo, useEffect } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { useGetAgoraConfigQuery, useGetAgoraVoicingListQuery, useLazyGetAgoraTokenQuery } from '../../app/services/server'; 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 { addVoiceMember, removeVoiceMember, updateConnectionState, updateDeafenStatus, updateMuteStatus, updateVoicingInfo, updateVoicingMember, updateVoicingNetworkQuality, upsertVoiceList } from '../../app/slices/voice';
import { useAppSelector } from '../../app/store'; import { useAppSelector } from '../../app/store';
import AudioJoin from '../../assets/join.wav'; import AudioJoin from '../../assets/join.wav';
+7 -5
View File
@@ -17,7 +17,7 @@ import { useAppSelector } from "../../../app/store";
import GoBackNav from "../../../common/component/GoBackNav"; import GoBackNav from "../../../common/component/GoBackNav";
import Members from "./Members"; import Members from "./Members";
import VoiceChat from "../VoiceChat"; import VoiceChat from "../VoiceChat";
import { updateChannelVisibleAside } from "../../../app/slices/channels"; import { updateChannelVisibleAside } from "../../../app/slices/footprint";
import Dashboard from "../VoiceChat/Dashboard"; import Dashboard from "../VoiceChat/Dashboard";
type Props = { type Props = {
cid?: number; cid?: number;
@@ -33,11 +33,13 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
userIds, userIds,
data, data,
loginUser, loginUser,
visibleAside
} = useAppSelector((store) => { } = useAppSelector((store) => {
return { return {
loginUser: store.authData.user, loginUser: store.authData.user,
userIds: store.users.ids, userIds: store.users.ids,
data: store.channels.byId[cid], data: store.channels.byId[cid],
visibleAside: store.footprint.channelAsides[cid]
}; };
}); });
useEffect(() => { useEffect(() => {
@@ -56,7 +58,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
const toggleMembersVisible = () => { const toggleMembersVisible = () => {
dispatch(updateChannelVisibleAside({ dispatch(updateChannelVisibleAside({
id: cid, 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} onClick={toggleMembersVisible}
> >
<Tooltip tip={t("channel_members")} placement="left"> <Tooltip tip={t("channel_members")} placement="left">
<IconPeople className={data.visibleAside == "members" ? "fill-gray-600" : ""} /> <IconPeople className={visibleAside == "members" ? "fill-gray-600" : ""} />
</Tooltip> </Tooltip>
</li> </li>
</ul> </ul>
@@ -125,10 +127,10 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
</header> </header>
} }
users={ users={
<Members uids={memberIds} addVisible={addVisible} cid={cid} ownerId={owner} membersVisible={data.visibleAside == "members"} /> <Members uids={memberIds} addVisible={addVisible} cid={cid} ownerId={owner} membersVisible={visibleAside == "members"} />
} }
voice={ voice={
<Dashboard visible={data.visibleAside == "voice"} id={cid} context="channel" /> <Dashboard visible={visibleAside == "voice"} id={cid} context="channel" />
} }
/>; />;
} }
+6 -5
View File
@@ -3,7 +3,7 @@
// import { useState } from 'react'; // import { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { updateChannelVisibleAside } from '../../../app/slices/channels'; import { updateChannelVisibleAside } from '../../../app/slices/footprint';
import { useAppSelector } from '../../../app/store'; import { useAppSelector } from '../../../app/store';
import IconHeadphone from '../../../assets/icons/headphone.svg'; import IconHeadphone from '../../../assets/icons/headphone.svg';
import Tooltip from '../../../common/component/Tooltip'; import Tooltip from '../../../common/component/Tooltip';
@@ -18,11 +18,12 @@ type Props = {
const VoiceChat = ({ id, context = "channel" }: Props) => { const VoiceChat = ({ id, context = "channel" }: Props) => {
const { joinVoice, joined, joining = false, joinedAtThisContext } = useVoice({ id, context }); const { joinVoice, joined, joining = false, joinedAtThisContext } = useVoice({ id, context });
const dispatch = useDispatch(); const dispatch = useDispatch();
const { loginUser, contextData, voiceList } = useAppSelector(store => { const { loginUser, voiceList, visibleAside } = useAppSelector(store => {
return { return {
loginUser: store.authData.user, loginUser: store.authData.user,
contextData: context == "channel" ? store.channels.byId[id] : store.users.byId[id], 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 }); const { data: agoraConfig } = useGetAgoraConfigQuery(undefined, { skip: !loginUser?.is_admin });
@@ -31,7 +32,7 @@ const VoiceChat = ({ id, context = "channel" }: Props) => {
if (context == "channel") { if (context == "channel") {
dispatch(updateChannelVisibleAside({ dispatch(updateChannelVisibleAside({
id, id,
aside: contextData.visibleAside == "voice" ? null : "voice" aside: visibleAside == "voice" ? null : "voice"
})); }));
} }
// todo DM // todo DM
@@ -51,7 +52,7 @@ const VoiceChat = ({ id, context = "channel" }: Props) => {
}; };
// 只有admin才能看到入口,后续会改 // 只有admin才能看到入口,后续会改
if (!loginUser || !loginUser.is_admin || !agoraConfig?.enabled) return null; 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 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 `; const badgeClass = `absolute -top-2 -right-2 w-4 h-4 rounded-full bg-primary-400 text-white `;
return ( return (