diff --git a/package.json b/package.json index a27161ca..03301951 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocechat-web", - "version": "0.7.43", + "version": "0.7.44", "homepage": "https://voce.chat", "dependencies": { "@metamask/onboarding": "^1.0.1", diff --git a/public/locales/en/setting.json b/public/locales/en/setting.json index 0e350270..2dda997c 100644 --- a/public/locales/en/setting.json +++ b/public/locales/en/setting.json @@ -73,6 +73,12 @@ "enable": "Enable", "disable": "Disable" }, + "enable_msg_url_preview": { + "title": "Enable URL Preview in Message", + "desc": "If enabled, url in message will show preview content.", + "enable": "Enable", + "disable": "Disable" + }, "guest_mode": { "title": "Guest Mode", "desc": "If enabled, visitors will see public channels on this server.", diff --git a/public/locales/zh/setting.json b/public/locales/zh/setting.json index d1cc2774..1aeb2271 100644 --- a/public/locales/zh/setting.json +++ b/public/locales/zh/setting.json @@ -64,6 +64,18 @@ "enable": "开启", "disable": "关闭" }, + "admin_see_group_members": { + "title": "只有管理员能看到群成员", + "desc": "如果开启,只有管理员能看到群成员,更好地保护隐私", + "enable": "开启", + "disable": "关闭" + }, + "enable_msg_url_preview": { + "title": "开启消息网址预览", + "desc": "如果开启,消息中的网址会显示预览内容", + "enable": "开启", + "disable": "关闭" + }, "guest_mode": { "title": "访客模式", "desc": "开启后,访客可以看到公共频道信息流", diff --git a/src/app/config.ts b/src/app/config.ts index 4adf3931..510ca7d7 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -186,4 +186,5 @@ export const getInviteLinkTimesList = () => [ } ]; export const KEY_ADMIN_SEE_CHANNEL_MEMBERS = `only_admin_can_see_channel_members`; +export const KEY_MSG_URL_PREVIEW = `enable_msg_url_preview`; export default BASE_URL; diff --git a/src/components/LinkifyText.tsx b/src/components/LinkifyText.tsx index 015d0950..91699403 100644 --- a/src/components/LinkifyText.tsx +++ b/src/components/LinkifyText.tsx @@ -5,6 +5,8 @@ import Linkify from "linkify-react"; import "linkify-plugin-mention"; import Mention from "./Message/Mention"; import URLPreview from "./Message/URLPreview"; +import useServerExtSetting from "@/hooks/useServerExtSetting"; +import { KEY_MSG_URL_PREVIEW } from "@/app/config"; type Props = { url?: boolean; @@ -25,8 +27,8 @@ const LinkifyText = ({ text, cid }: Props) => { - // const { t } = useTranslation(); - // const + const { getExtSetting } = useServerExtSetting({ successTip: false, key: KEY_MSG_URL_PREVIEW }); + const enablePreview = getExtSetting() && linkPreview; return ( {content} - {linkPreview && } + {enablePreview && } ); }, diff --git a/src/hooks/useServerExtSetting.ts b/src/hooks/useServerExtSetting.ts new file mode 100644 index 00000000..d11b48e3 --- /dev/null +++ b/src/hooks/useServerExtSetting.ts @@ -0,0 +1,55 @@ +import { useGetSystemCommonQuery, useUpdateSystemCommonMutation } from "@/app/services/server"; +import { useAppSelector } from "@/app/store"; +import { getJSONField, upsertJSON } from "@/utils"; +import { useEffect } from "react"; +import toast from "react-hot-toast"; +import { useTranslation } from "react-i18next"; +import { shallowEqual } from "react-redux"; + +// type Props = {}; + +const useServerExtSetting = (config?: { successTip?: boolean; key?: string }) => { + const { t } = useTranslation(); + const _config = Object.assign({}, { successTip: true, key: "" }, config); + const { refetch } = useGetSystemCommonQuery(); + const [updateSetting, { isSuccess }] = useUpdateSystemCommonMutation(); + + const jsonSetting = useAppSelector((store) => store.server.ext_setting ?? "{}", shallowEqual); + let setting = {}; + try { + setting = JSON.parse(jsonSetting); + } catch (error) {} + const defaultValueMap = { + string: "", + boolean: false + }; + const getExtSetting = (key?: string, type?: "string" | "boolean") => { + const _key = key ?? _config.key; + const _type = type ?? "boolean"; + return getJSONField(jsonSetting, _key) ?? defaultValueMap[_type]; + }; + const updateExtSetting = (key: string, value: any) => { + const json = upsertJSON(jsonSetting, { [key]: value }); + updateSetting({ ext_setting: json }); + }; + useEffect(() => { + if (isSuccess) { + refetch(); + } + }, [isSuccess]); + + useEffect(() => { + if (isSuccess && _config.successTip) { + toast.success(t("tip.update")); + } + }, [isSuccess, _config.successTip]); + + return { + jsonSetting, + setting, + getExtSetting, + updateExtSetting + }; +}; + +export default useServerExtSetting; diff --git a/src/routes/chat/ChannelChat/index.tsx b/src/routes/chat/ChannelChat/index.tsx index 419ab900..5309e673 100644 --- a/src/routes/chat/ChannelChat/index.tsx +++ b/src/routes/chat/ChannelChat/index.tsx @@ -21,20 +21,18 @@ import Members from "./Members"; import PinList from "./PinList"; import { getJSONField } from "@/utils"; import { KEY_ADMIN_SEE_CHANNEL_MEMBERS } from "@/app/config"; +import useServerExtSetting from "@/hooks/useServerExtSetting"; type Props = { cid?: number; dropFiles?: File[]; }; function ChannelChat({ cid = 0, dropFiles = [] }: Props) { + const { getExtSetting } = useServerExtSetting(); const { t } = useTranslation("chat"); const { pathname } = useLocation(); const navigate = useNavigate(); const dispatch = useDispatch(); - const serverExtSetting = useAppSelector( - (store) => store.server.ext_setting ?? "{}", - shallowEqual - ); const loginUser = useAppSelector((store) => store.authData.user, shallowEqual); const visibleAside = useAppSelector((store) => store.footprint.channelAsides[cid], shallowEqual); const userIds = useAppSelector((store) => store.users.ids, shallowEqual); @@ -67,8 +65,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) { const addVisible = loginUser?.is_admin || owner == loginUser?.uid; const pinCount = data?.pinned_messages?.length || 0; const toolClass = `relative cursor-pointer hidden md:block`; - const onlyAdminCanSeeMembers = - getJSONField(serverExtSetting, KEY_ADMIN_SEE_CHANNEL_MEMBERS) ?? false; + const onlyAdminCanSeeMembers = getExtSetting(KEY_ADMIN_SEE_CHANNEL_MEMBERS); const canViewMembers = loginUser?.is_admin ? true : !onlyAdminCanSeeMembers; return ( { + const { updateExtSetting, getExtSetting } = useServerExtSetting(); const { t } = useTranslation("setting"); - const { t: ct } = useTranslation(); - const { refetch } = useGetSystemCommonQuery(); - const serverExtSetting = useAppSelector( - (store) => store.server.ext_setting ?? "{}", - shallowEqual - ); - const [updateSetting, { isSuccess }] = useUpdateSystemCommonMutation(); - useEffect(() => { - if (isSuccess) { - refetch(); - toast.success(ct("tip.update")); - } - }, [isSuccess]); const handleChange = (newVal: boolean) => { - const json = upsertJSON(serverExtSetting, { [KEY_ADMIN_SEE_CHANNEL_MEMBERS]: newVal }); - updateSetting({ ext_setting: json }); + updateExtSetting(KEY_ADMIN_SEE_CHANNEL_MEMBERS, newVal); }; - const onlyAdminSeeChannelMembers = - getJSONField(serverExtSetting, KEY_ADMIN_SEE_CHANNEL_MEMBERS) ?? false; + const onlyAdminSeeChannelMembers = getExtSetting(KEY_ADMIN_SEE_CHANNEL_MEMBERS); return ( { + const { updateExtSetting, getExtSetting } = useServerExtSetting(); + const { t } = useTranslation("setting"); + const handleChange = (newVal: boolean) => { + updateExtSetting(KEY_MSG_URL_PREVIEW, newVal); + }; + const enable = getExtSetting(KEY_MSG_URL_PREVIEW); + return ( + + + { + handleChange(v == "true"); + }} + /> + + + ); +}; + +export default EnableMsgURLPreview; diff --git a/src/routes/setting/Overview/index.tsx b/src/routes/setting/Overview/index.tsx index 89162817..8ab2a1f3 100644 --- a/src/routes/setting/Overview/index.tsx +++ b/src/routes/setting/Overview/index.tsx @@ -17,6 +17,7 @@ import Server from "./Server"; import { shallowEqual } from "react-redux"; import OnlyAdminCreateGroup from "./OnlyAdminCreateGroup"; import OnlyAdminCanSeeChannelMembers from "./OnlyAdminSeeChannelMembers"; +import EnableURLPreviewInMsg from "./URLPreview"; export default function Overview() { const { t } = useTranslation("setting"); @@ -57,6 +58,7 @@ export default function Overview() { {/* 只有 admin 能创建群组 */} + {/* 访客模式 */}