feat: online status setting
This commit is contained in:
@@ -76,6 +76,10 @@
|
||||
"auto": "Auto",
|
||||
"dark": "Dark",
|
||||
"light": "Light"
|
||||
},
|
||||
"online_status": {
|
||||
"title": "Online Status",
|
||||
"desc": "Toggle users' online status visible"
|
||||
}
|
||||
},
|
||||
"license": {
|
||||
|
||||
@@ -68,6 +68,10 @@
|
||||
"auto": "自动",
|
||||
"dark": "黑夜模式",
|
||||
"light": "白天模式"
|
||||
},
|
||||
"online_status": {
|
||||
"title": "在线状态",
|
||||
"desc": "开启或关闭用户在线状态"
|
||||
}
|
||||
},
|
||||
"license": {
|
||||
|
||||
@@ -64,7 +64,17 @@ export const serverApi = createApi({
|
||||
},
|
||||
url: `/admin/system/version`,
|
||||
responseHandler: "text"
|
||||
})
|
||||
}),
|
||||
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
||||
try {
|
||||
const resp = await queryFulfilled;
|
||||
dispatch(
|
||||
updateInfo({ version: resp.data })
|
||||
);
|
||||
} catch {
|
||||
console.error("get server version error");
|
||||
}
|
||||
}
|
||||
}),
|
||||
getFirebaseConfig: builder.query<FirebaseConfig, void>({
|
||||
query: () => ({ url: `admin/fcm/config` })
|
||||
@@ -148,7 +158,17 @@ export const serverApi = createApi({
|
||||
}
|
||||
}),
|
||||
getSystemCommon: builder.query<SystemCommon, void>({
|
||||
query: () => ({ url: `admin/system/common` })
|
||||
query: () => ({ url: `admin/system/common` }),
|
||||
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
||||
try {
|
||||
const resp = await queryFulfilled;
|
||||
dispatch(
|
||||
updateInfo(resp.data)
|
||||
);
|
||||
} catch {
|
||||
console.error("get server common error");
|
||||
}
|
||||
}
|
||||
}),
|
||||
updateSystemCommon: builder.mutation<void, Partial<SystemCommon>>({
|
||||
query: (data) => ({
|
||||
@@ -383,5 +403,6 @@ export const {
|
||||
useGetAgoraConfigQuery,
|
||||
useGetAgoraVoicingListQuery,
|
||||
useUpdateSystemCommonMutation,
|
||||
useLazyGetSystemCommonQuery,
|
||||
useGetSystemCommonQuery
|
||||
} = serverApi;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Server } from "../../types/server";
|
||||
|
||||
export interface StoredServer extends Server {
|
||||
version: string,
|
||||
upgraded: boolean,
|
||||
logo: string;
|
||||
inviteLink?: {
|
||||
@@ -12,6 +13,7 @@ export interface StoredServer extends Server {
|
||||
webclient_auto_update: boolean
|
||||
}
|
||||
const initialState: StoredServer = {
|
||||
version: "",
|
||||
upgraded: false,
|
||||
name: "",
|
||||
description: "",
|
||||
@@ -33,6 +35,7 @@ const serverSlice = createSlice({
|
||||
},
|
||||
fillServer(state, action: PayloadAction<StoredServer>) {
|
||||
const {
|
||||
version = "",
|
||||
upgraded = false,
|
||||
inviteLink = {
|
||||
link: "",
|
||||
@@ -41,10 +44,10 @@ const serverSlice = createSlice({
|
||||
logo = "", // todo: check missed logo property
|
||||
name = "",
|
||||
description = "",
|
||||
show_user_online_status = false,
|
||||
show_user_online_status = true,
|
||||
webclient_auto_update = true
|
||||
} = action.payload || {};
|
||||
return { upgraded, name, logo, description, inviteLink, show_user_online_status, webclient_auto_update };
|
||||
return { version, upgraded, name, logo, description, inviteLink, show_user_online_status, webclient_auto_update };
|
||||
},
|
||||
updateInfo(state, action: PayloadAction<Partial<StoredServer>>) {
|
||||
const values = action.payload || {};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useGetServerVersionQuery } from '../../app/services/server';
|
||||
import { compareVersion } from '../utils';
|
||||
import { useAppSelector } from '../../app/store';
|
||||
|
||||
type Props = {
|
||||
empty?: boolean,
|
||||
@@ -11,8 +11,8 @@ type Props = {
|
||||
|
||||
const ServerVersionChecker = ({ empty = false, version, children }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { data: currentVersion, isSuccess } = useGetServerVersionQuery();
|
||||
if (!isSuccess) return null;
|
||||
const currentVersion = useAppSelector(store => store.server.version);
|
||||
if (!currentVersion) return null;
|
||||
const res = compareVersion(currentVersion, version);
|
||||
if (res < 0) return empty ? null : <div className='flex flex-col gap-2 items-start border border-solid border-orange-500 p-3 rounded-lg w-fit'>
|
||||
<span className='text-gray-400 text-sm'>
|
||||
|
||||
@@ -35,8 +35,8 @@ const User: FC<Props> = ({
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu();
|
||||
const { curr, loginUid } = useAppSelector((store) => {
|
||||
return { curr: store.users.byId[uid], loginUid: store.authData.user?.uid };
|
||||
const { curr, loginUid, showStatus } = useAppSelector((store) => {
|
||||
return { curr: store.users.byId[uid], loginUid: store.authData.user?.uid, showStatus: store.server.show_user_online_status };
|
||||
});
|
||||
const handleDoubleClick = () => {
|
||||
navigate(`/chat/dm/${uid}`);
|
||||
@@ -48,6 +48,7 @@ const User: FC<Props> = ({
|
||||
const statusClass = clsx(`absolute -bottom-[2.5px] -right-[2.5px] border-content rounded-full border-[1px] border-white dark:border-gray-300`,
|
||||
online ? "bg-green-500" : "bg-zinc-400",
|
||||
compact ? "w-[15px] h-[15px]" : "w-3 h-3");
|
||||
const statusElement = showStatus ? <div className={statusClass}></div> : null;
|
||||
if (!popover)
|
||||
return (
|
||||
<ContextMenu
|
||||
@@ -71,7 +72,7 @@ const User: FC<Props> = ({
|
||||
name={curr.name}
|
||||
alt="avatar"
|
||||
/>
|
||||
{curr.is_bot ? <IconBot className={clsx(compact && "absolute -bottom-[2.5px] -right-[2.5px]", "!w-[15px] !h-[15px]")} /> : <div className={statusClass}></div>}
|
||||
{curr.is_bot ? <IconBot className={clsx(compact && "absolute -bottom-[2.5px] -right-[2.5px]", "!w-[15px] !h-[15px]")} /> : statusElement}
|
||||
</div>
|
||||
{!compact && (
|
||||
<span className={nameClass} title={curr?.name}>
|
||||
@@ -111,7 +112,7 @@ const User: FC<Props> = ({
|
||||
name={curr.name}
|
||||
alt="avatar"
|
||||
/>
|
||||
<div className={statusClass}></div>
|
||||
{statusElement}
|
||||
</div>
|
||||
{!compact && (
|
||||
<span className={nameClass} title={curr?.name}>
|
||||
|
||||
@@ -2,14 +2,14 @@ import dayjs from "dayjs";
|
||||
import { FC, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Ring } from "@uiball/loaders";
|
||||
import { useGetServerVersionQuery } from "../../app/services/server";
|
||||
import Button from "./styled/Button";
|
||||
import { unregister } from '../../serviceWorkerRegistration';
|
||||
import { useAppSelector } from "../../app/store";
|
||||
type Props = {};
|
||||
const Version: FC<Props> = () => {
|
||||
const serverVersion = useAppSelector(store => store.server.version);
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
const { t } = useTranslation("setting", { keyPrefix: "version" });
|
||||
const { data: serverVersion } = useGetServerVersionQuery();
|
||||
const ts = (process.env.REACT_APP_BUILD_TIME ?? 0) as number;
|
||||
const handleSync = () => {
|
||||
setSyncing(true);
|
||||
|
||||
@@ -3,11 +3,12 @@ import dayjs from "dayjs";
|
||||
import initCache, { useRehydrate } from "../../app/cache";
|
||||
import { useLazyGetFavoritesQuery } from "../../app/services/message";
|
||||
import { useLazyGetUsersQuery } from "../../app/services/user";
|
||||
import { useLazyGetServerQuery } from "../../app/services/server";
|
||||
import { useGetServerVersionQuery, useGetSystemCommonQuery, useLazyGetServerQuery } from "../../app/services/server";
|
||||
import useStreaming from "./useStreaming";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
import { useLazyLoadMoreMessagesQuery } from "../../app/services/message";
|
||||
import useLicense from "./useLicense";
|
||||
import { compareVersion } from "../utils";
|
||||
// type Props={
|
||||
// guest?:boolean
|
||||
// }
|
||||
@@ -51,6 +52,10 @@ export default function usePreload() {
|
||||
getServer,
|
||||
{ isLoading: serverLoading, isSuccess: serverSuccess, isError: serverError, data: server }
|
||||
] = useLazyGetServerQuery();
|
||||
const { data: currServerVersion, isSuccess: serverVersionSuccess, isLoading: loadingServerVersion } = useGetServerVersionQuery();
|
||||
// 根据版本号判断是否需要调用system common api
|
||||
const skipSystemCommonApi = !(serverVersionSuccess && compareVersion(currServerVersion, '0.3.4') >= 0);
|
||||
useGetSystemCommonQuery(undefined, { skip: skipSystemCommonApi });
|
||||
useEffect(() => {
|
||||
initCache();
|
||||
rehydrate();
|
||||
@@ -87,9 +92,9 @@ export default function usePreload() {
|
||||
}, [canStreaming]);
|
||||
|
||||
return {
|
||||
loading: usersLoading || serverLoading || favoritesLoading || !rehydrated || loadingLicense,
|
||||
loading: usersLoading || serverLoading || favoritesLoading || !rehydrated || loadingLicense || loadingServerVersion,
|
||||
error: usersError && serverError && favoritesError,
|
||||
success: usersSuccess && serverSuccess && favoritesSuccess,
|
||||
success: usersSuccess && serverSuccess && favoritesSuccess && serverVersionSuccess,
|
||||
data: {
|
||||
users,
|
||||
server,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// import React from 'react'
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGetSystemCommonQuery, useUpdateSystemCommonMutation } from '../../../app/services/server';
|
||||
import { useEffect } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import Label from '../../../common/component/styled/Label';
|
||||
import Toggle from '../../../common/component/styled/Toggle';
|
||||
import { useAppSelector } from '../../../app/store';
|
||||
// type Props = {}
|
||||
|
||||
const Index = () => {
|
||||
const currStatus = useAppSelector(store => store.server.show_user_online_status);
|
||||
const { t } = useTranslation("setting", { keyPrefix: "overview.online_status" });
|
||||
const { t: ct } = useTranslation();
|
||||
const { data, isSuccess: loadSuccess, refetch } = useGetSystemCommonQuery();
|
||||
const [updateSetting, { isSuccess }] = useUpdateSystemCommonMutation();
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
refetch();
|
||||
toast.success(ct("tip.update"));
|
||||
}
|
||||
}, [isSuccess]);
|
||||
const handleToggle = () => {
|
||||
const opposite = !data?.show_user_online_status;
|
||||
updateSetting({ show_user_online_status: opposite });
|
||||
};
|
||||
if (!loadSuccess) return null;
|
||||
return (
|
||||
<div className="flex justify-between">
|
||||
<div className="text-sm">
|
||||
<div className="dark:text-gray-100 font-semibold">
|
||||
<Label className="dark:text-gray-200">{t("title")}</Label>
|
||||
</div>
|
||||
<span className="flex justify-between w-full text-gray-400" >{t("desc")}</span>
|
||||
</div>
|
||||
<Toggle
|
||||
onClick={handleToggle}
|
||||
checked={currStatus}
|
||||
></Toggle>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
@@ -9,6 +9,7 @@ import Language from './Language';
|
||||
import FrontendURL from "./FrontendURL";
|
||||
import DarkMode from "./DarkMode";
|
||||
import ServerVersionChecker from "../../../common/component/ServerVersionChecker";
|
||||
import OnlineStatus from "./OnlineStatus";
|
||||
|
||||
export default function Overview() {
|
||||
const { t } = useTranslation("setting");
|
||||
@@ -61,11 +62,16 @@ export default function Overview() {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ServerVersionChecker version="0.3.4" empty={true}>
|
||||
<OnlineStatus />
|
||||
</ServerVersionChecker>
|
||||
<ServerVersionChecker version="0.3.3" empty={true}>
|
||||
<FrontendURL />
|
||||
</ServerVersionChecker>
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
<Language />
|
||||
<DarkMode />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user