feat: online status setting

This commit is contained in:
Tristan Yang
2023-04-10 20:53:19 +08:00
parent 827ef76b16
commit 4cdcf502ff
10 changed files with 104 additions and 16 deletions
+4
View File
@@ -76,6 +76,10 @@
"auto": "Auto",
"dark": "Dark",
"light": "Light"
},
"online_status": {
"title": "Online Status",
"desc": "Toggle users' online status visible"
}
},
"license": {
+4
View File
@@ -68,6 +68,10 @@
"auto": "自动",
"dark": "黑夜模式",
"light": "白天模式"
},
"online_status": {
"title": "在线状态",
"desc": "开启或关闭用户在线状态"
}
},
"license": {
+23 -2
View File
@@ -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;
+5 -2
View File
@@ -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'>
+5 -4
View File
@@ -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 -2
View File
@@ -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);
+8 -3
View File
@@ -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;
+6
View File
@@ -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>