diff --git a/package.json b/package.json index 0d8872a0..a2eed7e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocechat-web", - "version": "0.9.92", + "version": "0.9.93", "homepage": "https://voce.chat", "dependencies": { "@metamask/onboarding": "^1.0.1", diff --git a/public/locales/en/chat.json b/public/locales/en/chat.json index bf4ad06b..0cdca4f3 100644 --- a/public/locales/en/chat.json +++ b/public/locales/en/chat.json @@ -76,5 +76,13 @@ "remark": "Add friend nickname", "remark_clear": "Reset friend nickname", "remark_intro": "Find a friend faster with a personal nickname. It will only be visible to you in your direct messages.", - "remark_placeholder": "Set Nickname" + "remark_placeholder": "Set Nickname", + + "guest_mode_warning": { + "title": "Guest Mode is Enabled", + "desc": "Unauthenticated visitors can see messages in public channels. You may disable guest mode or switch to a private channel instead.", + "disable_guest": "Disable Guest Mode", + "switch_private": "Switch to Private Channel", + "dont_remind": "Don't remind me again" + } } diff --git a/public/locales/zh/chat.json b/public/locales/zh/chat.json index f97d5bbd..d8f067f9 100644 --- a/public/locales/zh/chat.json +++ b/public/locales/zh/chat.json @@ -75,5 +75,13 @@ "remark": "备注", "remark_clear": "重置备注", "remark_intro": "给联系人备注,方便日后查找,备注仅您可见", - "remark_placeholder": "备注该用户" + "remark_placeholder": "备注该用户", + + "guest_mode_warning": { + "title": "访客模式已开启", + "desc": "未登录的访客可以看到公共频道的消息流。您可以前往关闭访客模式,或改为创建私有频道。", + "disable_guest": "关闭访客模式", + "switch_private": "改为私有频道", + "dont_remind": "不再提醒" + } } diff --git a/src/components/ChannelModal/index.tsx b/src/components/ChannelModal/index.tsx index 67a3c374..839eaffb 100644 --- a/src/components/ChannelModal/index.tsx +++ b/src/components/ChannelModal/index.tsx @@ -6,8 +6,10 @@ import i18n from "@/i18n"; import clsx from "clsx"; import { useCreateChannelMutation, useSendChannelMsgMutation } from "@/app/services/channel"; +import { useGetLoginConfigQuery, useUpdateLoginConfigMutation } from "@/app/services/server"; import { useAppSelector } from "@/app/store"; import { CreateChannelDTO } from "@/types/channel"; +import { LoginConfig } from "@/types/server"; import useFilteredUsers from "@/hooks/useFilteredUsers"; import ChannelIcon from "../ChannelIcon"; import Modal from "../Modal"; @@ -17,6 +19,44 @@ import StyledToggle from "../styled/Toggle"; import User from "../User"; import { shallowEqual } from "react-redux"; +const GUEST_WARNING_DISMISSED_KEY = "vocechat_public_channel_guest_warning_dismissed"; + +interface GuestModeWarningProps { + onDisableGuest: () => void; + onSwitchPrivate: () => void; + onDismiss: () => void; +} + +const GuestModeWarning: FC = ({ onDisableGuest, onSwitchPrivate, onDismiss }) => { + const { t } = useTranslation("chat"); + return ( +
+
+

+ {t("guest_mode_warning.title")} +

+

+ {t("guest_mode_warning.desc")} +

+
+ + + +
+
+
+ ); +}; + interface Props { personal?: boolean; closeModal: () => void; @@ -34,6 +74,10 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => { members: loginUser?.uid ? [loginUser.uid] : [], is_public: !personal }); + const [showGuestWarning, setShowGuestWarning] = useState(false); + + const { data: loginConfig } = useGetLoginConfigQuery(); + const [updateLoginConfig] = useUpdateLoginConfigMutation(); const { users, input, updateInput } = useFilteredUsers(); const [createChannel, { isSuccess, isError, isLoading, data: newChannel }] = @@ -45,17 +89,42 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => { return { ...prev, is_public: !is_public }; }); }; + + const doCreate = (channelData: CreateChannelDTO) => { + const payload = { ...channelData }; + if (payload.is_public) { + delete payload.members; + } + createChannel(payload); + }; + const handleCreate = () => { // todo: add field validation (maxLength, text format, trim) if (!data.name) { toast("please input channel name"); return; } - if (data.is_public) { - // 公共频道 不必有 members - delete data.members; + const guestEnabled = (loginConfig as LoginConfig | undefined)?.guest ?? false; + const warningDismissed = localStorage.getItem(GUEST_WARNING_DISMISSED_KEY) === "1"; + if (data.is_public && loginUser?.is_admin && guestEnabled && !warningDismissed) { + setShowGuestWarning(true); + return; } - createChannel(data); + doCreate(data); + }; + + const handleWarningDisableGuest = () => { + if (loginConfig) { + updateLoginConfig({ ...(loginConfig as LoginConfig), guest: false }); + } + setShowGuestWarning(false); + doCreate(data); + }; + + const handleWarningDismiss = () => { + localStorage.setItem(GUEST_WARNING_DISMISSED_KEY, "1"); + setShowGuestWarning(false); + doCreate(data); }; // todo: delete the following code and use common error handler instead @@ -101,7 +170,17 @@ const ChannelModal: FC = ({ personal = false, closeModal }) => { const loginUid = loginUser.uid; return ( -
+
+ {showGuestWarning && ( + { + setShowGuestWarning(false); + setData((prev) => ({ ...prev, is_public: false })); + }} + onDismiss={handleWarningDismiss} + /> + )} {!is_public && (