feat: auto delete msg setting

This commit is contained in:
Tristan Yang
2022-12-27 17:14:29 +08:00
parent 776b405781
commit 82eecc80b1
8 changed files with 124 additions and 83 deletions
@@ -39,6 +39,12 @@ export default async function handler({ operation, data = {}, payload }: Params)
await table?.setItem("readUsers", data.readUsers); await table?.setItem("readUsers", data.readUsers);
} }
break; break;
case "updateAutoDeleteSetting":
{
await table?.setItem("autoDeleteMsgUsers", data.autoDeleteMsgUsers || []);
await table?.setItem("autoDeleteMsgChannels", data.autoDeleteMsgChannels || []);
}
break;
default: default:
break; break;
} }
+17 -2
View File
@@ -1,7 +1,7 @@
import { createApi } from "@reduxjs/toolkit/query/react"; import { createApi } from "@reduxjs/toolkit/query/react";
// import toast from "react-hot-toast"; // import toast from "react-hot-toast";
import baseQuery from "./base.query"; import baseQuery from "./base.query";
import { updateMute } from "../slices/footprint"; import { updateAutoDeleteSetting, updateMute } from "../slices/footprint";
import { fillUsers } from "../slices/users"; import { fillUsers } from "../slices/users";
import BASE_URL, { ContentTypes } from "../config"; import BASE_URL, { ContentTypes } from "../config";
import { onMessageSendStarted } from "./handlers"; import { onMessageSendStarted } from "./handlers";
@@ -59,7 +59,22 @@ export const userApi = createApi({
url: `/user/burn-after-reading`, url: `/user/burn-after-reading`,
body: data, body: data,
method: "POST" method: "POST"
}) }),
async onQueryStarted(data, { dispatch, queryFulfilled }) {
try {
await queryFulfilled;
if (data.users) {
// users
dispatch(updateAutoDeleteSetting({ burn_after_reading_users: data.users }));
}
if (data.groups) {
// channel
dispatch(updateAutoDeleteSetting({ burn_after_reading_groups: data.groups }));
}
} catch {
console.log("update auto delete message setting error");
}
}
}), }),
updateMuteSetting: builder.mutation<void, MuteDTO>({ updateMuteSetting: builder.mutation<void, MuteDTO>({
+53 -4
View File
@@ -1,5 +1,6 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { MuteDTO } from "../../types/message"; import { MuteDTO } from "../../types/message";
import { AutoDeleteMessageSettingDTO, AutoDeleteMsgForGroup, AutoDeleteMsgForUser, AutoDeleteSettingForChannels, AutoDeleteSettingForUsers } from "../../types/sse";
export interface State { export interface State {
usersVersion: number; usersVersion: number;
@@ -8,6 +9,8 @@ export interface State {
readChannels: { [gid: number]: number }; readChannels: { [gid: number]: number };
muteUsers: { [uid: number]: { expired_in?: number } | undefined }; muteUsers: { [uid: number]: { expired_in?: number } | undefined };
muteChannels: { [gid: number]: { expired_in?: number } | undefined }; muteChannels: { [gid: number]: { expired_in?: number } | undefined };
autoDeleteMsgUsers: AutoDeleteMsgForUser[];
autoDeleteMsgChannels: AutoDeleteMsgForGroup[];
} }
const initialState: State = { const initialState: State = {
@@ -16,7 +19,9 @@ const initialState: State = {
readUsers: {}, readUsers: {},
readChannels: {}, readChannels: {},
muteUsers: {}, muteUsers: {},
muteChannels: {} muteChannels: {},
autoDeleteMsgUsers: [],
autoDeleteMsgChannels: [],
}; };
const footprintSlice = createSlice({ const footprintSlice = createSlice({
@@ -33,7 +38,9 @@ const footprintSlice = createSlice({
readUsers = {}, readUsers = {},
readChannels = {}, readChannels = {},
muteUsers = {}, muteUsers = {},
muteChannels = {} muteChannels = {},
autoDeleteMsgUsers = [],
autoDeleteMsgChannels = []
} = action.payload; } = action.payload;
return { return {
usersVersion, usersVersion,
@@ -41,7 +48,9 @@ const footprintSlice = createSlice({
readUsers, readUsers,
readChannels, readChannels,
muteUsers, muteUsers,
muteChannels muteChannels,
autoDeleteMsgUsers,
autoDeleteMsgChannels
}; };
}, },
updateUsersVersion(state, action: PayloadAction<number>) { updateUsersVersion(state, action: PayloadAction<number>) {
@@ -50,6 +59,45 @@ const footprintSlice = createSlice({
updateAfterMid(state, action: PayloadAction<number>) { updateAfterMid(state, action: PayloadAction<number>) {
state.afterMid = action.payload; state.afterMid = action.payload;
}, },
updateAutoDeleteSetting(state, action: PayloadAction<AutoDeleteMessageSettingDTO>) {
const payload = action.payload;
Object.keys(payload).forEach((key) => {
switch (key) {
case "burn_after_reading_users": {
const updates = (payload as AutoDeleteSettingForUsers).burn_after_reading_users;
updates.map(item => {
const { uid } = item;
const idx = state.autoDeleteMsgUsers.findIndex(tmp => tmp.uid == uid);
if (idx !== -1) {
// update
state.autoDeleteMsgUsers[idx] = item;
} else {
// add
state.autoDeleteMsgUsers.push(item);
}
});
break;
}
case "burn_after_reading_groups": {
const updates = (payload as AutoDeleteSettingForChannels).burn_after_reading_groups;
updates.map(item => {
const { gid } = item;
const idx = state.autoDeleteMsgChannels.findIndex(tmp => tmp.gid == gid);
if (idx !== -1) {
// update
state.autoDeleteMsgChannels[idx] = item;
} else {
// add
state.autoDeleteMsgChannels.push(item);
}
});
break;
}
default:
break;
}
});
},
updateMute(state, action: PayloadAction<MuteDTO>) { updateMute(state, action: PayloadAction<MuteDTO>) {
const payload = action.payload || {}; const payload = action.payload || {};
Object.keys(payload).forEach((key) => { Object.keys(payload).forEach((key) => {
@@ -111,7 +159,8 @@ export const {
updateUsersVersion, updateUsersVersion,
updateReadChannels, updateReadChannels,
updateReadUsers, updateReadUsers,
updateMute updateMute,
updateAutoDeleteSetting
} = footprintSlice.actions; } = footprintSlice.actions;
export default footprintSlice.reducer; export default footprintSlice.reducer;
+12 -7
View File
@@ -3,6 +3,7 @@ import { toast } from 'react-hot-toast';
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useUpdateAutoDeleteMsgMutation } from "../../app/services/user"; import { useUpdateAutoDeleteMsgMutation } from "../../app/services/user";
import { useAppSelector } from '../../app/store';
import SaveTip from "./SaveTip"; import SaveTip from "./SaveTip";
import StyledRadio from "./styled/Radio"; import StyledRadio from "./styled/Radio";
@@ -10,11 +11,15 @@ import StyledRadio from "./styled/Radio";
type Props = { type Props = {
id: number, id: number,
type?: "user" | "channel", type?: "user" | "channel",
expires_in?: number // expires_in?: number
} }
const AutoDeleteMessages = ({ id, type = "channel", expires_in = 0 }: Props) => { const AutoDeleteMessages = ({ id, type = "channel" }: Props) => {
const setting = useAppSelector(store => type == "channel" ?
store.footprint.autoDeleteMsgChannels.find(item => item.gid == id)
:
store.footprint.autoDeleteMsgUsers.find(item => item.uid == id));
const [updateSetting, { isSuccess }] = useUpdateAutoDeleteMsgMutation(); const [updateSetting, { isSuccess }] = useUpdateAutoDeleteMsgMutation();
const [value, setValue] = useState(expires_in); const [value, setValue] = useState<number>(setting?.expires_in ?? 0);
const { t } = useTranslation("setting", { keyPrefix: "auto_delete_msg" }); const { t } = useTranslation("setting", { keyPrefix: "auto_delete_msg" });
const options = [ const options = [
{ title: t("off"), value: 0 }, { title: t("off"), value: 0 },
@@ -29,7 +34,7 @@ const AutoDeleteMessages = ({ id, type = "channel", expires_in = 0 }: Props) =>
updateSetting(dto); updateSetting(dto);
}; };
const handleReset = () => { const handleReset = () => {
setValue(expires_in); setValue(setting?.expires_in ?? 0);
}; };
const handleChange = (val: number) => { const handleChange = (val: number) => {
setValue(val); setValue(val);
@@ -39,7 +44,7 @@ const AutoDeleteMessages = ({ id, type = "channel", expires_in = 0 }: Props) =>
toast.success("Update Successfully!"); toast.success("Update Successfully!");
} }
}, [isSuccess]); }, [isSuccess]);
const originalVal = setting?.expires_in ?? 0;
return ( return (
<section className="max-w-[512px] h-full relative"> <section className="max-w-[512px] h-full relative">
<div className="text-sm"> <div className="text-sm">
@@ -50,11 +55,11 @@ const AutoDeleteMessages = ({ id, type = "channel", expires_in = 0 }: Props) =>
<StyledRadio <StyledRadio
options={options.map(({ title }) => title)} options={options.map(({ title }) => title)}
values={options.map(({ value }) => value)} values={options.map(({ value }) => value)}
value={value} value={value || 0}
onChange={handleChange} onChange={handleChange}
/> />
</div> </div>
{expires_in !== value && <SaveTip saveHandler={handleSave} resetHandler={handleReset} />} {originalVal !== value && <SaveTip saveHandler={handleSave} resetHandler={handleReset} />}
</section> </section>
); );
}; };
+18 -1
View File
@@ -13,7 +13,8 @@ import {
updateUsersVersion, updateUsersVersion,
updateReadChannels, updateReadChannels,
updateReadUsers, updateReadUsers,
updateMute updateMute,
updateAutoDeleteSetting
} from "../../../app/slices/footprint"; } from "../../../app/slices/footprint";
import { updateUsersByLogs, updateUsersStatus } from "../../../app/slices/users"; import { updateUsersByLogs, updateUsersStatus } from "../../../app/slices/users";
import { resetAuthData, updateLoginUser } from "../../../app/slices/auth.data"; import { resetAuthData, updateLoginUser } from "../../../app/slices/auth.data";
@@ -179,6 +180,22 @@ export default function useStreaming() {
} }
} }
break; break;
case "burn_after_reading_users":
{
const arr = data[key];
if (arr) {
dispatch(updateAutoDeleteSetting({ burn_after_reading_users: arr }));
}
}
break;
case "burn_after_reading_groups":
{
const arr = data[key];
if (arr) {
dispatch(updateAutoDeleteSetting({ burn_after_reading_groups: arr }));
}
}
break;
default: default:
break; break;
@@ -1,62 +0,0 @@
import { useState, useEffect } from 'react';
import { toast } from 'react-hot-toast';
import { useTranslation } from "react-i18next";
import { useUpdateAutoDeleteMsgMutation } from "../../app/services/user";
import SaveTip from "../../common/component/SaveTip";
import StyledRadio from "../../common/component/styled/Radio";
type Props = {
id: number,
type?: "user" | "channel",
expires_in?: number
}
const AutoDeleteMessages = ({ id, type = "channel", expires_in = 0 }: Props) => {
const [updateSetting, { isSuccess }] = useUpdateAutoDeleteMsgMutation();
const [value, setValue] = useState(expires_in);
const { t } = useTranslation("setting", { keyPrefix: "auto_delete_msg" });
const options = [
{ title: t("off"), value: 0 },
{ title: t("30_seconds"), value: 30 },
{ title: t("10_min"), value: 10 * 60 },
{ title: t("1_hour"), value: 60 * 60 },
{ title: t("1_day"), value: 24 * 60 * 60 },
{ title: t("1_week"), value: 7 * 24 * 60 * 60 },
];
const handleSave = () => {
const dto = type == "user" ? { users: [{ uid: id, expires_in: value }] } : { groups: [{ gid: id, expires_in: value }] };
updateSetting(dto);
};
const handleReset = () => {
setValue(expires_in);
};
const handleChange = (val: number) => {
setValue(val);
};
useEffect(() => {
if (isSuccess) {
toast.success("Update Successfully!");
}
}, [isSuccess]);
return (
<section className="max-w-[512px] h-full relative">
<div className="text-sm">
<h2 >{t("title")}</h2>
<p className="text-gray-500">{t("desc")}</p>
</div>
<div className="mt-4">
<StyledRadio
options={options.map(({ title }) => title)}
values={options.map(({ value }) => value)}
value={value}
onChange={handleChange}
/>
</div>
{expires_in !== value && <SaveTip saveHandler={handleSave} resetHandler={handleReset} />}
</section>
);
};
export default AutoDeleteMessages;
+1 -1
View File
@@ -1,7 +1,7 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Overview from "./Overview"; import Overview from "./Overview";
import AutoDeleteMessages from './AutoDeleteMessages'; import AutoDeleteMessages from '../../common/component/AutoDeleteMessages';
import ManageMembers from "../../common/component/ManageMembers"; import ManageMembers from "../../common/component/ManageMembers";
export interface NavItem { export interface NavItem {
+17 -6
View File
@@ -46,17 +46,28 @@ export interface MuteChannel {
gid: number; gid: number;
expired_at: number; expired_at: number;
} }
export type AutoDeleteMsgForUser = {
uid: number; expires_in: number | null
}
export type AutoDeleteMsgForGroup = {
gid: number; expires_in: number | null
}
export interface UserSettingsEvent { export interface UserSettingsEvent {
type: "user_settings"; type: "user_settings";
mute_users?: MuteUser[]; mute_users?: MuteUser[];
mute_groups?: MuteChannel[]; mute_groups?: MuteChannel[];
read_index_users?: { uid: number; mid: number }[]; read_index_users?: { uid: number; mid: number }[];
read_index_groups?: { gid: number; mid: number }[]; read_index_groups?: { gid: number; mid: number }[];
burn_after_reading_users?: { uid: number; expires_in: number }[]; burn_after_reading_users?: AutoDeleteMsgForUser[];
burn_after_reading_groups?: { gid: number; expires_in: number }[]; burn_after_reading_groups?: AutoDeleteMsgForGroup[];
} }
export type AutoDeleteSettingForUsers = {
burn_after_reading_users: AutoDeleteMsgForUser[]
}
export type AutoDeleteSettingForChannels = {
burn_after_reading_groups: AutoDeleteMsgForGroup[]
}
export type AutoDeleteMessageSettingDTO = AutoDeleteSettingForUsers | AutoDeleteSettingForChannels
export interface UserSettingsChangedEvent { export interface UserSettingsChangedEvent {
type: "user_settings_changed"; type: "user_settings_changed";
from_device?: string; from_device?: string;
@@ -66,8 +77,8 @@ export interface UserSettingsChangedEvent {
remove_mute_groups?: number[]; remove_mute_groups?: number[];
read_index_users?: { uid: number; mid: number }[]; read_index_users?: { uid: number; mid: number }[];
read_index_groups?: { gid: number; mid: number }[]; read_index_groups?: { gid: number; mid: number }[];
burn_after_reading_users?: { uid: number; expires_in: number }[]; burn_after_reading_users?: AutoDeleteMsgForUser[];
burn_after_reading_groups?: { gid: number; expires_in: number }[]; burn_after_reading_groups?: AutoDeleteMsgForGroup[];
} }
export interface RelatedGroupsEvent { export interface RelatedGroupsEvent {